I'm using the ADC module of a PIC16LF15355 MCU. When I initiate the ADC conversion after setting the ADCON0bits.GOnDONE bit, I loop and wait for the bit to clear. It never clears, even when running the setup time out to several milliseconds. I have successfully implemented the same code (except for setup) on a PIC16LF15344 without any problems. I included the relevant code below. So what can cause the ADC to not complete a conversion?

#pragma config RSTOSC = HFINT32 // Reset oscillator set to internal HF
#define _XTAL_FREQ    4000000   // 4 MHz oscillator freq for delay functions
#define NUM_ADC_CHANS 9

uint8_t spiOutBuf[10];

int main( void ) {
    OSCFRQbits.HFFRQ = 0b010; // Set internal HF oscillator frequency to 4 MHz
    WPUA   = 0b00100000;      // Disable all weak pull-ups on port except RA5
    WPUC   = 0b11000000;      // Enable weak pull-ups on RC6 & RC7 (switch inputs)
    TRISA  = 0b11111111;      // Set all port A bits as inputs
    ANSELA = 0b11011111;      // Set all port A bits as analog except RA5
    TRISC  = 0b11000011;      // Set port C RC0, RC1, RC6, RC7 as inputs (analog & switches)
    ANSELC = 0b00000011;      // Set port C RC0, RC1 as analog (flex sensor inputs)

    // Initialize ADC
    ADCON0 = 0x00;            // Clear ADCON0 to default settings
    ADCON1 = 0x00;            // Clear ADCON1 to default settings
    FVRCONbits.ADFVR = 0b10;  // ADC FVR buffer gain 2x (2.048V)
    FVRCONbits.FVREN = 1;     // Enable Fixed Voltage Reference
    ADCON1bits.ADFM = 0;      // Left-justified results in ADRESH
    ADCON1bits.ADPREF = 0b11; // Vref+ is FVR
    ADCON1bits.ADCS = 0b101;  // Fosc/16 conversion clock selected
    ADACTbits.ADACT = 0b00000; // Auto-conversion disabled
    PIE1bits.ADIE = 1;        // Enable ADC interrupts
    PIR1bits.ADIF = 0;        // clear ADC interrupt flag
    INTCONbits.GIE = 1;       // Enable global interrupts
    INTCONbits.PEIE = 1;      // Enable peripheral interrupts

    while(1) {
        for ( uint8_t chan = 0; chan < NUM_ADC_CHANS; chan++ )
            spiOutBuf[chan + 1] = ADC_read( chan );

            // Write the SPI buffer to the device...

uint8_t ADC_read( uint8_t chan ) {
    const uint8_t ADC_port_map[NUM_ADC_CHANS] = {
    0b00000000,   // RA0
    0b00000100,   // RA1
    0b00001000,   // RA2
    0b00101100,   // RA3
    0b00010000,   // RA4
    0b00011100,   // RA7
    0b00011000,   // RA6
    0b01000000,   // RC0
    0b01000100    // RC1

    // Set the ADC channel using the register mask from the port map.
    if ( chan < NUM_ADC_CHANS )
        ADCON0 = ADC_port_map[chan];
    ADCON0bits.ADON = 1;         // Turn on the ADC
    PIR1bits.ADIF = 0;           // Clear the A/D interrupt flag
    __delay_us( 20 );            // Delay for acquisition time
    ADCON0bits.GOnDONE = 1;      // Start an A-to-D conversion
    while (ADCON0bits.GOnDONE == 1);  // Wait for conversion to complete
    PIR1bits.ADIF = 0;           // Clear the A/D interrupt flag
    ADCON0bits.ADON = 0;         // Turn OFF ADC
    return ( ADRESH );           // Return higher 8 bits of the ADC result
  • \$\begingroup\$ If I understand how the PIC ADC module works, the only thing that I can think of that would prevent the conversion from completing is if the ADC never receives a clock. Perhaps there is something different about ADC setup in the 16LF15355 that I have missed. The only other thing that I can think of is static discharge damage to the chip, or heat damage to the chip during SMD soldering, but that seems like an awfully long shot. \$\endgroup\$ – Zizumara Jul 7 at 5:05
  • \$\begingroup\$ You have ADC interrupts enabled. Where's your ISR? \$\endgroup\$ – Bruce Abbott Jul 7 at 7:44
  • \$\begingroup\$ Are you sure it's 'GOnDONE' and not 'GODONE' or 'GO'? Also as @Bruce mentioned you've enabled interrupts but you have no ISR. You don't need to enable interrupts to poll the GO/DONE bit. What I think might be happening is that when the conversion finishes it triggers the interrupt but there's no ISR to handle it so it just jumps to nowhere and can't return. Since you said you've implemented this same code elsewhere however then try changing the bit name first then disabling interrupts. If that falls make an ISR. \$\endgroup\$ – Simeon R Jul 7 at 9:06

Thanks for the response. Yes, it was the fact that I had ADC interrupts enabled with no ISR. After disabling interrupts, setting and polling the GOnDONE bit now works. As for GOnDONE versus GO, the PIC header file defines both for the same bit, and either one works. Perhaps they do this to maintain compatibility with other versions or libraries.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.