PIC ADC reading a few % low - Page 1
Forum section: electronics / general

author: chilternview
author_rank: Frequent Contributor
timestamp: February 27, 2025, 04:38:58 pm
content: I'm trying to use a 16F1789 PIC to, amongst other things, measure a voltage.The voltage is around 25.6v wrt ground, and so I'm using a potential divider of a 22k and 3.9k to give a value of around 3.85v (which I've measured and also checked for nooise with a scope); the PIC ADC reference is 4.096v from the FVR.However, the ADC is giving a result of about 3715 so about 4% low. I've tried a lower impedance divider network (2.2k and 390ohms) but that made no difference.The code looks like this:Code:// Use port E as analogANSELE = 1;// disable weak pullupsWPUE = 0;TRISEbits.TRISE0 = 1; // input to ADC// Set up vref// bit 7 = FVREN volt ref enabled// bit 6 = FVRRDY ref ready flag// bit 5 = TSEN temp sense enable// bit 4 = TSRNG temp sense range// bit 3-2 = CDAFVR comp and DAC FVR off// bit 1-0 = ADFVR adc fvr selection = 4.096vFVRCON = 0b10000011;// Enable ADON, set i/p channel, set GO/DONE_ to 0// bit 7 = ADRMD 0=12 bit// bit 6-2 = CHS +ve i/p channel RE0 = AN5 = 00101// bit 1 = GO/DONE_// bit 0 = ADONADCON0 = 0b00010101;// Wait 30uS for FVR to stabilise after enable__delay_us(30);// bit 7 = ADFM = 1 (2's complement) or 0 (sign/mag)// bit 6-4 = ADCS clock cycle = FOsc/64 110// bit 3 = n/a// bit 2 = ADNREF 0 = vref- is vss// bit 1-0 = ADPREF 11 = vref+ connected to FVRADCON1 = 0b11100011;// bit 7-4 TRIGSEL disabled// bit 3-0 CHSN 1111 = selected by ADNREFADCON2 = 0b00001111;// Set GO/DONE_, wait for conversionADCON0bits.GO_nDONE = 1;while (! ADCON0bits.DONE) {__delay_us(1);}// if ADFM = 1 we have 2's complement result in ADRESH:ADRESLint16_t result = ADRES;sprintf(ads, "%d", result);uart_puts(ads);// Turn off ADCADCON0bits.ADON=0;I'm using a 20MHz xtal clock, did try a 16MHz clock just in case, even though the docs indicate that FOsc/64 is OK at 20MHz for the ADC conversion. Is there something I'm missing?

author: Ian.M
author_rank: Super Contributor
timestamp: February 27, 2025, 04:59:26 pm
content: Yep. Microchip MCU internal FVR references are cr@p!See datasheet setion 31.3 DC Characteristics, TABLE 31-1: SUPPLY VOLTAGE, parameter D003, which says the 4.086V FVR option is +/-5%, so your 4% low result is within spec!You *could* try sending the FVR voltage to the DAC and setting the DAC to full scale so you can measure 255/256 of the FVR voltage at a pin, but that uses a different PGA to the FVR -> ADC routing so may differ slightly from the refernce voltage the ADC is getting.Your best option for low cost, medium accuracy applications is probably to calibrate out the error in software or tweak the divider to calibrate it out in hardware. For high accuracy applications use a precision external reference!

author: coppice
author_rank: Super Contributor
timestamp: February 27, 2025, 05:09:26 pm
content: What is the tolerance of the resistors you used for the divider? You need to add that to the 5% tolerance of the reference. I can't see a temperature coefficient for the reference in the Microchip data sheet. Its not clear if the 5% tolerance they quote applies over the whole temperature range.

author: Kjelt
author_rank: Super Contributor
timestamp: February 27, 2025, 05:09:32 pm
content: Indeed low cost in bytes solution is to measure 16 or 32 values and either put the correction in a look up table or better put the values in excel and see if a nice linear curve can be found and implement that function for correction.

author: chilternview
author_rank: Frequent Contributor
timestamp: February 27, 2025, 05:10:11 pm
content: Thanks Ian, I did notice that 5% in the spec and assumed it wouldn't be right on the edge!Oh well, I might look into using an external reference if I can find something cheap as chips to do that, or maybe just calibrate it out in s/w.

author: chilternview
author_rank: Frequent Contributor
timestamp: February 27, 2025, 05:12:43 pm
content: Quote from: coppice on February 27, 2025, 05:09:26 pmresistors are 1%, but I measure the divider output at 3.850v whereas the ADC is consistently giving readings 0.9-1.0v below.

author: 8goran8
author_rank: Contributor
timestamp: February 27, 2025, 06:12:32 pm
content: Some revisions of the PIC16F1788/PIC16F1789 microcontroller have FVR Output tolerance of ± 8%.https://ww1.microchip.com/downloads/en/DeviceDoc/80000575B.pdf

author: Andy Watson
author_rank: Super Contributor
timestamp: February 27, 2025, 06:35:43 pm
content: Quote from: chilternview on February 27, 2025, 04:38:58 pmA delay between selecting the ADC channel and starting the conversion. I don't know what the specs for the 1788 are, but the lesser members of the family require time to charge/stabalise their internal capacitances.

author: chilternview
author_rank: Frequent Contributor
timestamp: February 27, 2025, 06:49:34 pm
content: Quote from: Andy Watson on February 27, 2025, 06:35:43 pmIsn't the 30uS delay in the correct place?

author: Andy Watson
author_rank: Super Contributor
timestamp: February 27, 2025, 07:58:46 pm
content: Perhaps I've misinterpreted the code. I was looking at this section:Code:// bit 3-0 CHSN 1111 = selected by ADNREFADCON2 = 0b00001111;// Set GO/DONE_, wait for conversionADCON0bits.GO_nDONE = 1;

author: PCB.Wiz
author_rank: Super Contributor
timestamp: February 27, 2025, 08:57:34 pm
content: Quote from: chilternview on February 27, 2025, 05:10:11 pmWhat powers the PIC ?Many regulators these days are way better than that 5% (or the 8% above)1% and 2% are more common specs.

author: chilternview
author_rank: Frequent Contributor
timestamp: February 27, 2025, 09:34:38 pm
content: It's run off USB +5v. So not wonderfully regulated.A LM4040 4.096v reference looks like a cheap way to improve the accuracy.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 04, 2025, 06:18:11 pm
content: Really, the options are external reference, or calibrating the internal one (prepare to add temperature compensation as well!)Since MCU ADCs usually have quite decent linearity, and noise can be filtered if high data rate is not needed, an external reference is usually the easiest upgrade one can do to improve absolute accuracy, and is less hassle than interfacing with external ADC. You can get something much better than 5% for $0.20 or so.

author: Roehrenonkel
author_rank: Frequent Contributor
timestamp: March 05, 2025, 06:49:44 am
content: Hi chilternview,have you tried a cap (1n...100nF) at the ADC-input?Good luck

author: H.O
author_rank: Frequent Contributor
timestamp: March 09, 2025, 07:17:24 am
content: Late to the party here but another thing to note is the recommended impedence of the source feeding the ADC input (which, for the 178x family, is 10k).What if, instead of 22k/3k9, you tried 2k2/390 for the voltage divider?