PIC12 - ADC never returning zero - Page 1
Forum section: electronics / general

author: SmokyMcToad
author_rank: Contributor
timestamp: July 25, 2016, 08:53:03 pm
content: Hi Everyone,I am trying to read a 10K(linear)potentiometer using the ADC of a PIC12F1572(http://ww1.microchip.com/downloads/en/DeviceDoc/40001723D.pdf). The pot-meter is connected directly to the ADC of the PIC using the same VCC and GND that is supplied to the PIC. But for some reason I am getting weird results when I read low voltages.Reading 'high' voltage (~5V) works great; I get 1023 as expected(using the 'ADC1_GetConversion()' function that was generated by MPlab). And when rotating the pot-meter the ADC result changes accordingly as far as I can see. But when I turn the pot completely down, I only get 44 from the ADC while the voltage on the ADC pin is around 0.1mV according to my(cheap)multimeter. Directly connecting the ADC pin to GND or using a different PIC12F1572 did not make a difference; the ADC still did not go lower as 44.I've gone through the datasheet and the Code Configurator settings but sofar I have not been able to find anything that would explain this. Is there some additional setting needed when measuring low voltages on a PIC? Or do I need to add something to my test-circuit since it contains only a bare pot-meter at the moment.ADC settings used:Code:Clock: FOSC/16 (sampling freq. 86.9565 kHz, conversiontime 11.5us)Alignment: rightPositive reference: VDD(No triggers or interrupts)Code (that was generated) to retrieve ADC value:Code:adc_result_t ADC1_GetConversion(adc_channel_t channel){ADCON0bits.CHS = channel; // select the A/D channelADCON0bits.ADON = 1; // Turn on the ADC module__delay_us(ACQ_US_DELAY); // Acquisition time delayADCON0bits.GO_nDONE = 1; // Start the conversionwhile (ADCON0bits.GO_nDONE) // Wait for the conversion to finish{}return ((ADRESH << 8) + ADRESL); // Conversion finished, return the result}Edit: changed subject to better reflect question

author: dannyf
author_rank: Super Contributor
timestamp: July 25, 2016, 10:18:43 pm
content: 1. Your pot may not go to 0v.2. Your ADC may have an offset.3. Your ADC may not read 0v exactly at 0....To check for sure, ground that pin and see what you have.

author: Signal32
author_rank: Frequent Contributor
timestamp: July 25, 2016, 10:25:40 pm
content: Is your circuit on a breadboard ?Can you share an exact schematic ?What are you using as voltage reference for the ADC ?

author: SmokyMcToad
author_rank: Contributor
timestamp: July 25, 2016, 10:27:55 pm
content: Hi Danny,I've already tried connecting to ground; ADC still read 44 unfortunately.But an offset is possible I guess; I will see if I can find some info from Microchip.Edit:@DannyI've checked for offset but sofar it seems to stop at the expected 1023 when 5V is applied; it never reaches 1024 or higher. So for some reason the range seems to be limited to 44-1023 instead of the full 0-1023.

author: SmokyMcToad
author_rank: Contributor
timestamp: July 25, 2016, 10:36:31 pm
content: @Signal32:Yes, the PIC is mounted on a breadboard. I don't have an schematic around, but I did not connect much to it so hopefully a description of the pins will make my setup clear enough:- PIN1 is connected to 5V (using a 7805 from a 12V supply)- PIN2 is not connected- PIN3 is set to ADC channel 3: this pin is connected to the middle pin of the pot- PIN4 is not connected- PIN5 is digital output; I use this to light a led depending on ADC value ('if (ADCresult == 1023) RA2=1' etc.)- PIN6 is PWM output; not connected, but it is generating a pulse (disabling PWM did not seem to affect the ADC result for 0V)- PIN7 is not connected- PIN8 is connected to GNDThe first and third pin of the pot are connected to the same 5V and GND as the PIC.The ADC voltage reference is set to use VDD.(PS: The pickit3 is also connected to the PIC, but disconnecting it did not seem to help either)edit: fixed typo

author: ludzinc
author_rank: Unknown
timestamp: July 25, 2016, 11:42:40 pm
content: Assuming you're using your 5V rail as your reference, 44 ~= 200mV.What's the voltage at the input pin of your micro with respect to the ground pin on your micro?What's the voltage of the 'ground' pin of your pot, with respect to the ground pin of the micro?With a 10k pot, a 200mV offset on your board equates to around 400 ohms of stray impedance. How good it he ground connection of your micro to your system ground?

author: StillTrying
author_rank: Super Contributor
timestamp: July 26, 2016, 02:08:16 am
content: Unlike some others,I realise you're connecting the input to 0V, and you can't get much lower than that.Sure the osc is at 16MHz and not 32MHz.Even at 16Mhzconversiontime 11.5usis right on the limit, so you might have to try FOSC/32 even if it's just for testing.Double or treble ACQ_US_DELAY just for testing.ANSELx set correctly.Page 112 says something about:Analog input functions, such as ADC and comparatorinputs, are not shown in the priority lists. These inputsare active when the I/O pin is set for Analog mode usingthe ANSELx registers. Digital output functions maycontrol the pin when it is in Analog mode with thepriority shown below in Table 11-2.Can't think of any others why you can't get below 44.

author: mikerj
author_rank: Super Contributor
timestamp: July 26, 2016, 12:50:23 pm
content: Quote from: StillTrying on July 26, 2016, 02:08:16 amExcept that 0v is not always 0v; a potential difference of 200mV on a cheap breadboard is not difficult to achieve, assuming the OP has used one. If he has literally connected the ADC pin directly to the PIC Vss pin (i.e. not some random point of the circuit that eventually connects to the Vss pin) and got the same result then it's time to look at the ADC code.

author: Kalvin
author_rank: Super Contributor
timestamp: July 26, 2016, 01:00:43 pm
content: Have you tried increasing the acquisition time delay?Code:__delay_us(ACQ_US_DELAY); // Acquisition time delay

author: Kalvin
author_rank: Super Contributor
timestamp: July 26, 2016, 01:05:20 pm
content: Have you tried to put the chip into a low power mode during the ADC measurement? Atmega328p device have noise issues unless the device is put into a low power mode during ADC operation. This may be applicable to the PIC's too, but not sure though. Just an idea.

author: SmokyMcToad
author_rank: Contributor
timestamp: July 26, 2016, 04:41:36 pm
content: @Ludzinc & MikerJThanks for the suggestions; I've now measured the resistance and this appears to be around 0.2Ohm from the groundingpoint to the actual ground on the powersupply. As you suggested I've also connected the ADC pin directly to the GND pin, but the adc result was still 44.@KalvinThanks; I've checked the acquisition delay but after setting it to FOSC/64 with ACQ_US_DELAY*4 there was no difference in the output.I've also tried using another pin(PIN7 which is connected to adc channel 0)and here I get 40 as lowest value from the ADC(while PIN3 gives 44). The same code was used, so I wondering if this is simply the lowest adcResult I can get on this batch of chips(since another chip I tried (same type) had the same issue). Is it possible for PIC chips to have these kind of 'offset' issues in the ADC peripheral itself?

author: JPortici
author_rank: Super Contributor
timestamp: July 26, 2016, 05:18:24 pm
content: There should be the gain/offset error also with INL and DNL on the electrical specification section of the datasheet... but 44 of offset error is A LOT.are you able tocarefullyapply a negative voltage at the analog input? (with a current limiting resistor) and see wether you can get to 0PAGE 278 for the ADC characteristicAnyways as it was already stated i would increase the sampling time.. try and substitute that with like __delay_us(1000), a millisecond or so.. not too much, but not too little.something that could happen... your 5V is happily oscillating because you are in a breadboard so your voltage reference is NOT stable.Using the FVR and test if with a stable reference you can get to 0VI remember having a simillar problem like 6-7 years ago but i can't remember how i solved the problem

author: SmokyMcToad
author_rank: Contributor
timestamp: July 26, 2016, 05:43:04 pm
content: @JPorticiThanks; tested it immediately and the results are definitely interesting; at FVRx4 (4.096Vref) I get around 51 and at FVRx1 (1.024Vref) it jumps a bit between 211 and 212.So it keeps measuring a value of around 200mV although I don't have a clue yet where this voltage is coming from.Edit:Unfortunately I don't have any reliable negative voltage available to test with.

author: Signal32
author_rank: Frequent Contributor
timestamp: July 26, 2016, 06:14:29 pm
content: Quote from: SmokyMcToad on July 26, 2016, 05:43:04 pmYou only need a battery(or any floating power supply) + a pot to create a negative voltage.Connect the + of the battery to the ground of your circuit.Then connect both of the ends of the pot to the ends of the battery.The center of the pot is now your negative adjustable voltage.PS You wouldn't want to apply more than -0.3v of voltage to the pin.

author: SmokyMcToad
author_rank: Contributor
timestamp: July 26, 2016, 06:39:10 pm
content: @Signal32 & JPortici:Thanks for the negative voltage tips!! Used a 1.5V battery and now the ADC goes down completelyI had to apply around -0.218V so that seems to fit my earlier measurements.But does this mean the internal negative Vref of the PIC is not working correctly? Or can my breadboard still be the cause? (Would adding a trim-pot to the GND of the PIC help?)Edit:Adding a pot to the GND of the PIC did work; turning it till I got a voltage difference of around 200mV and the ADC started returning 0. But I guess this is not a great solution as I would need to 'raise' the GND pins of all connected devices. Is there any other way to get a (small) negative voltage without using a battery? Or would I need to use a LM317 (or similar) for that?

author: mikerj
author_rank: Super Contributor
timestamp: July 26, 2016, 09:29:27 pm
content: Do you have a second PIC to test? It seems possible you have a faulty device as the offset is far higher than I would expect.

author: JPortici
author_rank: Super Contributor
timestamp: July 26, 2016, 09:35:48 pm
content: I think i got ithttp://www.microchip.com/forums/m905272.aspxreply #16you might have the pullups enabled and those would raise the voltage enough to cause your error, or at least some part of it(i don't think it was what happened to me that one time, as it happened with an ages old 16f876a)

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: July 26, 2016, 09:42:19 pm
content: Quote from: SmokyMcToadThe ADC only has 10 bits, so itcan'tgo higher than 1023. Turn the pot until it just gets to 1023. Is the analog input voltage nowexactlyequal to Vdd, or significantly lower?Set the DAC output to 0 Volts and measure it internally via ADC channel 30. What do you get?

author: StillTrying
author_rank: Super Contributor
timestamp: July 27, 2016, 03:29:17 pm
content: using a different PIC12F1572 did not make a difference; the ADC still did not go lower as 44.It seems odd for 2 to haveexactlythe same problem.When you swapped ICs, are you sure you didn't somehow manage to put the same one back in. I somehow managed it once.

author: SmokyMcToad
author_rank: Contributor
timestamp: July 27, 2016, 04:17:17 pm
content: @StillTrying:Yep; the new one was not programmed yet so it would not even blink the led when i plugged it in.@Bruce:Correct; but I was testing to see if some offset was applied that increased the adc-result with 44 across the whole range. But nothing exceeded 1023 so I knew there was no general offset applied.@Jportici:You Sir are my hero!!(And now I also know what 'WPU' means in the code configurator)After disabling the weak pullup the adcResult was jumping between 0 and 1 when directly connected to GNDMany thanks to you all for helping!edit: typo

author: matseng
author_rank: Frequent Contributor
timestamp: July 27, 2016, 05:17:37 pm
content: It's very un-intuitive that pullups aren't automatically disabled for a pin set as analog input.... But there's a lot of gotchas in the world of microcontrollers so one have to read and understand every damn sentence of the datasheets and not make any assumptions at all.

author: Howardlong
author_rank: Super Contributor
timestamp: July 27, 2016, 08:32:03 pm
content: In the meantime, I found myself with a bit of time this evening, only to find this has been solved! I have little trust in MCC, every time I use it I find a new bug, so I built up a board and wrote the following.Another problem with MCC is that it makes source code distribution more painful as even the most trivial blinky project is in half a dozen source files.My "board" differs from yours in that I use RA5 as the PWM1 output, I used the primary PWM1 pin for the debugger.Code:// PIC12F1572 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FOSC = INTOSC // (INTOSC oscillator; I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)// CONFIG2#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)#pragma config LPBOREN = OFF // Low Power Brown-out Reset enable bit (LPBOR is disabled)#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#define _XTAL_FREQ 16000000#include <stdint.h>static volatile uint16_t _u16ADCResult=0; // volatile to stop optimising outvoid main(void){// Basic chip initialisationOSCCONbits.IRCF=0b1111; // 16MHz in INTOSCANSELA=0; // All digital (for now anyway)// Setup pinsTRISAbits.TRISA2=0; // LEDAPFCONbits.P1SEL=1; // Send PWM1 to RA5, I'm using the primary pin for debuggingTRISAbits.TRISA5=0; // PWM, alternate pinTRISAbits.TRISA4=1; // RA4 == AN3ANSELAbits.ANSA4=1; // Analogue in// ADC setupADCON0bits.CHS=0b00011; // 0b00011 -> Ch3ADCON1bits.ADFM=1; // 1 -> Right justifiedADCON1bits.ADCS=0b110; // 0b110 -> Tad == Fosc/64 == 4usADCON1bits.ADPREF=0b00; // 0b00 -> Vrpos == VddADCON0bits.ADON=1;// PWM setupPWM1PR=1023; // Match ADC range for total period countPWM1OF=0; // Offset not used in our case.PWM1PH=0; // Start at phase=0PWM1DC=0; // For starters, ADC will change thisPWM1TMR=0; // Initialise to be safePWM1CONbits.MODE=0b00; // 0b00 -> Standard PWMPWM1CONbits.OE=1; // Output enablePWM1CLKCONbits.CS=0b00; // 0b00 -> FOSCPWM1CLKCONbits.PS=0b000; // 0b000 -> Prescaler 1:1PWM1CONbits.EN=1;while(1){__delay_us(5); // Sample timeADCON0bits.ADGO=1; // Start conversionLATAbits.LATA2=1; // LED onwhile (ADCON0bits.ADGO) // Wait for conversion to finish{NOP(); // I like NOPs so I can place debugger breakpoints}LATAbits.LATA2=0; // LED off_u16ADCResult=ADRES; // Get the ADC resultPWM1DC=_u16ADCResult; // Set the new duty cyclePWM1LDCONbits.LDA=1; // Trigger a PWM reload next period start}}

author: dannyf
author_rank: Super Contributor
timestamp: July 27, 2016, 11:10:33 pm
content: "adcResult was jumping between 0 and 1 when directly connected to GND"The last bit of an ADC makes a great random number generator.

author: StillTrying
author_rank: Super Contributor
timestamp: July 28, 2016, 01:11:54 am
content: I did think of the weak pull-up, but the 210mV would mean that the wpu is installed 1K to 2K up towards the ADC, - doesn't make much sense.

author: dannyf
author_rank: Super Contributor
timestamp: July 28, 2016, 01:38:28 am
content: QuoteI agree.especially when you consider that the adc read 44 with the input grounded: hard to imagine any pull-up to overcome a short to ground.

author: Doomkeks
author_rank: Newbie
timestamp: June 16, 2019, 05:45:31 pm
content: Just a side note on this topic. I stumbled upon it by googling my problem during my mayhem today:I got into PIC ADC for the first time today, also with the PIC12F1572. Programming in XC8 C, also for the first time.No matter what I did, the ADC always read about 0.4V too low. At the same time it was fluctuating quite a bit without touching anything. I thought I did some stupid rookie mistake.I was trying all kind of power supplies, ways of coding, voltage references and what not for a whole day. As a last ditch, I swapped out the PIC for a different identical one.Aaaand yep, that was it. I had a faulty PIC.I wish I tried this earlier. So keep that in mind.