calibadc manipulation

Akat

New Member
in 40x1 we have calibadc.. i don't know to manipulate the codes after it.. can anyone show my any example? letsay

main:
calibadc
readadc 0,b0
'the code here will be the processing of the data
let b1 = b0*5/255
'then codes here is to show the data on screen
serout bla bla bla.....
goto main

if the voltage ref is exactly around 5, so i can always use b0*5, but when the ref down to 4 or something, how do i manipulate that expression to something that times to the voltage ref all the time? and how calibadc works here? and i know its about 0.6v testing, but the way we can manipulate the codes makes me dizzy on howto...

sorry for my english :)
 

Technical

Technical Support
Staff member
To use calibadc you read the value into a a variable

symbol calib_value = b1
calibadc calib_value

The formula is

(0.6 / Vsupply) x 255 = calib_value

so

Vsupply is approximately 153 / calib_value
 
Last edited:

Akat

New Member
ic... :) thanks... i've got it...

symbols vref = b3
main:
calibadc b0
vref = 153/b0
readadc 0,b1
let b2 = b1*vref/255
goto main

thankyou very2 much
 

hippy

Ex-Staff (retired)
Assumimg the maths is right ...

The Vsupply can be determined from "CALIBADC Nref" as follows -

Vref = ( Nref / 255 ) * Vsupply

Vsupply = ( Vref * 255 ) / Nref


The Vadc from "READADC pin,Nadc" can then be determined as follows -

Vadc = ( Nadc / 255 ) * Vsupply

Vadc = ( Nadc / 255 ) * ( Vref * 255 / Nref )

Vadc = ( Nadc * Vref ) / Nref


We know Vref is 0.6, or 6/10 so -

Vadc = ( Nadc * 6 / 10 ) / Nref

Which can be better used as -

Vadc = ( Nadc * 6 / Nref ) / 10

The whole program would then be -

Code:
Symbol Nref = b0
Symbol Nadc = b1
Symbol Vadc = b2

CalibAdc Nref
ReadAdc PIN, Nadc
Vadc = Nadc * 6 / Nref / 10
SerTxd( "Voltage = ", #Vadc, "V", CR, LF )
For greater resolution -

Code:
Symbol Nref = b0
Symbol Nadc = b1
Symbol Vadc = b2
Symbol Vdec = b3

CalibAdc Nref
ReadAdc PIN, Nadc
Vadc = Nadc * 6 / Nref / 10
Vdec = Nadc * 6 / Nref // 10
SerTxd( "Voltage = ", #Vadc, ".", #Vdec, "V", CR, LF )
 

Akat

New Member
wow, thanx hippy... i never imagine that it can go this complicated.. im gonna try this tonight.. :)
 

MartinM57

Moderator
I've just used Hippy's code on my 40X1 and get:

Vcc = 5.03V (bench power supply, digital multimeter)
V at ADC 5 (leg 8) = 1.691V (same digital multimeter)

Nref = 28
Nadc = 85

So according to Vadc = ( Nadc * 6 / Nref ) / 10, then using perfect maths (not Picaxe maths) my Vadc is being measured via a calibrated ADC as 1.821 volts - not that close :(

If you ignore the calibadc effect and just take the plain Nadc number then:
Vadc = 85 / 255 * 5.03 = 1.676 volts - which is much closer

If I'm understanding properly, an Nref value of 28 indicates:
Vref = 28 / 255 * 5.03 = 0.55 volts

The connected device is a 3-axis accelerometer with a restricted output voltage range so accuracy is very important!

Thoughts?
 
Last edited:

MartinM57

Moderator
Just tried this
Code:
#PICAXE 40X1 
Symbol Nref = b0
Symbol Nadc = b1
Symbol Wref = w5
Symbol Wadc = w6

again:
CalibAdc Nref
ReadAdc 5, Nadc

CalibAdc10 Wref
ReadAdc10 5, Wadc

SerTxd( "Nref = ", #Nref, CR, LF )
SerTxd( "Nadc = ", #Nadc, CR, LF )
SerTxd( "Wref = ", #Wref, CR, LF )
SerTxd( "Wadc = ", #Wadc, CR, LF )

pause 2000
goto again
and got
Code:
Nref = 28
Nadc = 85
Wref = 115
Wadc = 342
Which gives:
- uncorrected ReadADC10 voltage = 342 / 1023 * 5.05 = 1.681 volts (measured as 1.691 volts)
- corrected ReadADC10 voltage = 342 * 6 / 115 / 10 = 1.784 volts

So not really much better...:confused:
 

hippy

Ex-Staff (retired)
Hmm. I did double check my maths, so perhaps there's something else going on.

Getting Nref=28 from CalibAdc is odd, in real world maths, reading 0.6V with a 5.03V supply from ReadAdc ( which is what I believe CalibAdc does ) should give ...

(0.6/5.03)*255 = 30.42 = 30 when rounded down.

I'd already looked at what errors the rounding down would cause but didn't mention that so as to not cloud the issue. That's a 1.5% inherent error which will affect subsequent calculations, CalibAdc10 should do far better with a much lower error.

However, we're not worried about subsequent errors yet, and that 28 is a long way from 30. I can see three possibilities for the discrepency in order of IMO most likely ...

1) Not using the Enhanced Download Interface with serial cable connected. CalibAdc will likely be affected just as ReadAdc can be.

2) Not using a calibrated multimeter. Being out by near 0.5V (10%) as would be needed to get 28 seems unlikely.

3) The PICAXE Firmware isn't reading the 0.6V reference correctly.

However again, getting Nadc=85 fits with what would be expected ...

(1.691/5.03)*255 = 85.77 = 85 when rounded down.

On to the word readings, Wref=115, should be ...

(0.6/5.03)*1023 = 122.03 = 122 when rounded down - Even further out !

For Wadc=342, should be ...

(1.691/5.03)*1023 = 343.92 = 343 rounded down.

That's not exact but quite close. It looks like the primary error is coming in for the CalibAdc/CalibAdc10 values.

=====

If the Nref and Wref were what the theory predicted then,

Nadc * 6 / Nref / 10 = Vadc

85 * 6 / 30 / 10 = 1.7 - close to 1.691 ( within 1.5% )

342 * 6 / 122 /10 = 1.6 - Again close ( same result with 343 )

So I think that proves the maths is okay given the rounding errors.
 
Last edited:

hippy

Ex-Staff (retired)
I don't have a 28X1/40X1 configured at present, but it could be worth trying multiple CalibAdc's to see if that affects things ...

- CalibAdc b0
- CalibAdc b1
- CalibAdc b2
- SerTxd( #b0, " ", #b1, " ", #b2, CR, LF )

More adventerous would be poking SFR to take a direct reading of Vref bypassing the PICAXE firmware.

If calibrated ADC were required it could also be achieved by ignoring CalibAdc and putting a voltage reference on a normal ADC pin and using the same theory, "CalibAdc b0" is the same as "ReadAdc VREF_PIN,b0".

PS : To get round not having an Enhanced Download Circuit, put a long pause at the start and the SerTxd in a loop. Download/reset the chip, unplug cable, let it take its readings, then plug he serial cable back in.
 
Last edited:

MartinM57

Moderator
1) Always use the enhanced download circuit - have done for all the years :eek: I've been Picaxe'ing - seen too many others have problems!

2) I have 3 digital multimeters (don't ask!) - I've just dug the the other two out the cupboard and the three read, for Vcc and the voltage on leg 8:
5.03 and 1.71
5.01 and 1.70
5.03 and 1.71

They're not quite the same readings as earlier - I moved the PCB and didn't put it back in the same place (the accelerometer measures absolute G so the X, Y, Z vectors of the PCB matter), but for this set of readings the values are:
Code:
Nref = 28
Nadc = 86
Wref = 115
Wadc = 346
 

MartinM57

Moderator
Ran this:
Code:
pause 1000
start:
SerTxd("disconnect cable now and reconnect in 10 seconds time!", CR, LF )
pause 5000
CalibAdc b0
CalibAdc b1
CalibAdc b2
pause 10000
SerTxd("b0 = ", #b0, " b1 = ", #b1, " b2 = ", #b2, CR, LF )
goto start
and got this:
Code:
disconnect cable now and reconnect in 10 seconds time!
b0 = 28 b1 = 28 b2 = 28
disconnect cable now and reconnect in 10 seconds time!
b0 = 28 b1 = 28 b2 = 28
disconnect cable now and reconnect in 10 seconds time!
b0 = 28 b1 = 28 b2 = 28
disconnect cable now and reconnect in 10 seconds time!
b0 = 28 b1 = 28 b2 = 28
disconnect cable now and reconnect in 10 seconds time!
 

hippy

Ex-Staff (retired)
Taking everything else out, I'd have to put it down to some sort of problem with the CalibAdc command. The theory indicates 30 at 8-bit and 122 at 10-bit should be returned.

Turning it upside-down, a CalibAdc reading should deliver 30 for any Vsupply between 4.94V and 5.1V.

Untested, but while you're at it, this may be interesting to play with ...

Code:
        Symbol  ADRESH  = $1E
        Symbol  ADCON0  = $1F
        Symbol  ADRESL  = $9E
        Symbol  ADCON1  = $9F

        Pause 2000              ' Long enough to get Terminal up and running

        ReadAdc 5,b0            ' Configure most ADC SFR's settings

        Peek ADCON1,b0          ' Set Vcc/Vss as references
        bit4 = 0
        bit5 = 0
' ====  bit7 =                  ' 8-bit/10-bit
        Poke ADCON1,b0

        Peek ADCON0,b0          ' Turn on ADC, Select Vref I/P
        bit0 = 1
        bit2 = 1
        bit3 = 1
        bit4 = 1
        bit5 = 1
' ====  bit6 =                  ' Conversion Timing
' ====  bit7 =                  ' Conversion Timing
        Poke ADCON0,b0

        Peek ADCON0,b0          ' Initiate conversion
        bit1 = 1
        Poke ADCON0,b0

        Do                      ' Wait for conversion completed
          Peek ADCON0,b0
        Loop Until bit1 = 0

        Peek ADRESH,b1
        Peek ADRESL,b0

        Sertxd ( "Nref = ",#b1," ",#b0,CR,LF )
 

MartinM57

Moderator
Output from exactly what you proposed is
Code:
Nref = 28 192
...not that I'm sure what it means. I left the commented out "bits" commented out..

Got to go out now and do some socialising (it's called a "party" apparently - so SWMBO just told me) - be back tomorrow :)
 

hippy

Ex-Staff (retired)
That's interesting and useful. The lhs (28) is the raw Nref reading at 8-bits, as CalibAdc returns. The rhs (192/$C0) are the two lsb's of the 10-bit reading shifted into the two msb's of the second byte; (28*4)+(192/64)=115, as CalibAdc10 gives. So that test reads exactly as CalibAdc and CalibAdc10 do.

The two bits to play with are bit6/bit7 of ADCON0. The ideal results you want to see are "30 128".
 

BCJKiwi

Senior Member
I have also carried out the same sort of tests as MartinM57 with similar results. However to simplify the test, the supply voltage was applied to the readadc pin directly.

CalibADC10 always returns a voltage that is too high. So it would appear there is an issue with the constants used internally by the calibadc command.
Just read the last few posts - it looks as if the error is in the chip unless Rev-Ed are settng those register values somehow.

Have found another issue while testing which relates to the // operator - it drops any leading zeros in the decimal portion!!

e.g. a value of 5025 / 1000 --> 5.025 but in PICAXE math 5025 // 1000 produces an output of 25.

This is reproduced in the simulator so it is not the sertxd/Ascii conversion that is causing the issue.
Hence the code variation using DIG which does generate the correct decimal output.

So rather than fiddling with the registers (which presumably you would have to do each tim ethe program started up), have modified the code to apply a correction factor.

The following code produces a value which matches the DMM readings to within +- 0.01V for supply from the range of 4.25 through 5.1V on the 28X1 fw Ver A.1 PICAXE under test
Code:
#picaxe 28x1
SetFreq em16
symbol ADC_CAL = w0  '0.6v Internal Calibration Reference voltage
symbol ADC_VAR = w1  'Variable voltage being tested
symbol VOLT = w2
symbol VOLTC = w3  'Correction
pause 5000
'
calibadc10 ADC_CAL
ReadADC10 3,ADC_VAR
VOLT = ADC_VAR * 60 / ADC_CAL  ' 1023 * 60 / 123 = 499.024
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd("Voltage = ",b10,".",b11,b12,"V",CR,LF)
VOLTC = VOLT * 38 / 1000   ' 499 * 25 / 1000 = 12.47
VOLT = VOLT - voltC    ' 499 - 12 = 487
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd("Voltage = ",b10,".",b11,b12,"V",CR,LF)
Accuracy is important with external devices like the accelerometer which have their own internal voltage regulators. However a calibration check should be made on them anyway as the readout from an accelerometer can be affected by geographical location (direction and curvature of earth's magnetic field at your location). If this is done, then I'm not sure sure that the error is an issue any longer as the problem seems to be with the calibadc not with readadc, and the voltage coming from the external device is relative to its internally regulated voltage - or have I missed a step in logic there?
See post #19 below for correction.
 
Last edited:

hippy

Ex-Staff (retired)
@ MartimM57 : here's the next code you need to try. No changes needed ( ideal for after a heavy night partying ), just run, and report back ...

Code:
        Symbol  ADRESH  = $1E
        Symbol  ADCON0  = $1F
        Symbol  ADRESL  = $9E
        Symbol  ADCON1  = $9F

        Pause 2000              ' Long enough to get Terminal up and running

        For b2 = 0 To 3

        ReadAdc 5,b0            ' Configure most ADC SFR's settings

        Peek ADCON1,b0          ' Set Vcc/Vss as references
        bit4 = 0
        bit5 = 0
' ====  bit7 =                  ' 8-bit/10-bit
        Poke ADCON1,b0

        Peek ADCON0,b0          ' Turn on ADC, Select Vref I/P
        bit0 = 1
        bit2 = 1
        bit3 = 1
        bit4 = 1
        bit5 = 1
        bit6 = b2 & 1 MAX 1     ' Conversion Timing
        bit7 = b2 & 2 MAX 1     ' Conversion Timing
        Poke ADCON0,b0

        Peek ADCON0,b0          ' Initiate conversion
        bit1 = 1
        Poke ADCON0,b0

        Do                      ' Wait for conversion completed
          Peek ADCON0,b0
        Loop Until bit1 = 0

        Peek ADRESH,b1
        Peek ADRESL,b0

        Sertxd ( #b2, " Nref = ",#b1," ",#b0,CR,LF )

        Next
 

BCJKiwi

Senior Member
@ Hippy
Just run this for you,

Results are

0 Nref = 29 0
1 Nref = 29 64
2 Nref = 29 64
3 Nref = 29 0


Not 30 and 128 yet!
 

hippy

Ex-Staff (retired)
Thanks, a slight shift but nothing really, and all results consistent, so I guess just a minor Vsupply change has altered that.

I found the errata sheet and there is an issue with reading Fixed Vref ( VP6 as Microchip call it ) but it's not clear exactly what consequential effects it has, although they provide a workround.

http://ww1.microchip.com/downloads/en/DeviceDoc/80302D.pdf

You can try replacing the "Turn ADC on ..." with -

Code:
        Peek ADCON0,b0          ' Turn on ADC, Select Vref I/P
        Symbol VRCON = $97
	Poke VRCON,%00100000    ' Set VCREF = 0V
        bit0 = 1
        bit2 = 0
        bit3 = 1
        bit4 = 1
        bit5 = 1
        Poke ADCON0,b0
        bit2 = 1
        Poke ADCON0,b0
I'm off to bed now, so no rush and no follow-up for 8 hours or so. ( "Boing", said Zebbedee )
 

BCJKiwi

Senior Member
Since (presumably) this would need to be applied each time you run the program (to modify whatever Rev_Ed have in their firmware or the editor), then I think its probably easier to run with the in-code correction (as per my post #15) until Technical chimes in and advises if it's something they can sort.

Using this;
Code:
symbol ADC_CAL = w0      '0.6v Internal Calibration Reference voltage
symbol ADC_VAR = w1      'Variable voltage being tested
symbol VOLT = w2
symbol VOLTC = w3       'Correction
pause 5000
'
'supply voltage
calibadc10 ADC_CAL
ReadADC10 3,ADC_VAR     ' VSupply
VOLT = ADC_VAR * 60 / ADC_CAL    ' 1023 * 60 / 123 = 499.024
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd ("Supply Voltage = ",b10,".",b11,b12,"V")
'
VOLTC = VOLT * 38 / 1000      ' 499 * 38 / 1000 = 18.96
VOLT = VOLT - voltC        ' 499 - 18 = 481
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd ("   Corrected = ",b10,".",b11,b12,"V",CR,LF)'
'
'
'Sensor Voltage
ReadADC10 1,ADC_VAR     ' VSupply
VOLT = ADC_VAR * 60 / ADC_CAL    ' 1023 * 60 / 123 = 499.024
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd ("Sensor Voltage = ",b10,".",b11,b12,"V")
'
VOLTC = VOLT * 38 / 1000      ' 499 * 38 / 1000 = 18.96
VOLT = VOLT - voltC        ' 499 - 18 = 481
b10= VOLT DIG 2 +"0"
b11= VOLT DIG 1 +"0"
b12= VOLT DIG 0 +"0"
SerTxd ("   Corrected = ",b10,".",b11,b12,"V",CR,LF)'
These results were obtained - the sensor was an accelerometer
Code:
Supply Voltage = 5.24V   Corrected = 5.05V
Sensor Voltage = 1.79V   Corrected = 1.73V      Sensor DMM 1.73
 
Supply Voltage = 5.20V   Corrected = 5.01V
Sensor Voltage = 1.78V   Corrected = 1.72V      Sensor DMM 1.73
 
Supply Voltage = 5.20V   Corrected = 5.01V
Sensor Voltage = 1.78V   Corrected = 1.72V      Sensor DMM 1.73
 
Supply Voltage = 5.20V   Corrected = 5.01V
Sensor Voltage = 1.78V   Corrected = 1.72V      Sensor DMM 1.73
So I think this confirms that corrections need to be made even if the external device has it's own internal regulator.

The above discussion gives the corrected voltage which is generally not relevant as program actions are usually taken on the readadc value and not converted to an actual voltage.

For practical use, this suggests a correction should be applied to the readadc immediately it is received so the corrected value is available for the program where the readadc value is used.

Thus a practical working code snippet (for testing with readout) could be;
Code:
readadc10 1,w0
SerTxd ("Sensor readadc = ",#w0)
w1 = w0 * 38 /1000
w0 = w0 - w1
b10= w0 DIG 2 +"0"
b11= w0 DIG 1 +"0"
b12= w0 DIG 0 +"0"
SerTxd ("    Corrected readadc = ",#w0,cr,lf)
but all you actually need in a working program is,
Code:
readadc10 1,w0         ' the line that's already in the program
w1 = w0 * 38 /1000     '3.8% error correction
w0 = w0 - w1           'since we have an error that produces too high a result, the correction is subtracted.
The 38 / 1000 represents a 3.8 percent error correction.

This is just two lines more than would typically be used without corrections.

These confirming results were obtained.
Code:
Supply Voltage = [B][I]5.[COLOR=black]24[/COLOR]V[/I][/B]   Corrected = 5.05V
Sensor Voltage = 1.74V   Corrected = [B][I]1.68V[/I][/B]
Sensor readadc = 341     Corrected readadc = [B][I]329[/I][/B]

Initially these results don't appear correct but the check calculation is;
1023 / 5.24 * 1.68 = 327.98 (with a calculator) which I presume is correct once integer math has been factored in.

So we now need some more tests on different 28X1s and 40X1s to see if this factor (38/1000, i.e. 3.8 %) is consistent, or if each chip needs to be individually calibrated.
 
Last edited:

MartinM57

Moderator
BJCKiwi...
Running the code at the top of your post #19 code I get:
Code:
Supply Voltage = 5.33V   Corrected = 5.13V
Sensor Voltage = 1.77V   Corrected = 1.71V
DMM measured as 5.02 and 1.685

...so not 3.8% for me
 
Last edited:

MartinM57

Moderator
Hippy...

Running your code at #16 I get
Code:
0 Nref = 28 192
1 Nref = 28 192
2 Nref = 28 192
3 Nref = 28 192
So different from BJC's....
 

BCJKiwi

Senior Member
MartinM57...
That suggests the error in your 40X1 is higher so you will need to increase the 38 until you get a match to your measured results.

In theory you can get the correction factor directly from the numbers you have;
(5.33 - 5.02) / 5.33 * 1000 = 58.16 so try 58 in place of the 38 and see if it gives you the 5.02 or 1.685 you should have.

I found a little further tinkering gave the right result - integer math strikes again!

If Hippy's adjustment can be got right (I don't really follow what's happening there), then even though it looks more complicated, it would only need to be done once at initialisation.

Alternatively the correction could be applied in line each time readadc is used.

Either way it looks like each chip would need to be calibrated if the level of accuracy is required, or a variable power supply (battery) is involved - all depends on the application.
 
Last edited:

MartinM57

Moderator
55 or 56 does it for me (trial and error and both give the same answer)
Code:
Supply Voltage = 5.33V   Corrected = 5.04V
Sensor Voltage = 1.76V   Corrected = 1.67V
Measured at 5.03 and 1.677
 

hippy

Ex-Staff (retired)
Applying hard-wired correction does indeed work, but of course only for the environment the correction is written for. That said, the environment ( whatever Vsuppy is mainly ) should be fairly consistent across runs on that particular hardware, it just has to be different correction on different hardware. In fact, hared-wired correction is what would have to be done if there were no CalibAdc available and how it's always been done in the past ... or by using an external voltage reference and ReadAdc to emulate CalibAdc.

The later is the only accurate choice if the PICAXE supply isn't regulated. CalibAdc simply saves on having to supply ones own voltage eference source.

It is pointless to try and do correction using CalibAdc if the results returned by CalibAdc are not correct. Note also that CalibAdc results will be different for eveyone because it varies depending upon Vsupply, so not getting the same results does not show anything much except when Vsupply is also given.

Using CalibAdc should be the best way to correct readings as it saves all the tortuous maths in having to determine the hard-wired correction equation and should work even when Vsupply changes where the hard-wired correction would start introducing errors. I'd also recommend using CalibAdc frequently rather than just once so any changes in the chip are automatically accounted for, as Vsupply and temperature changes and so on during use.

I'm at a loss as to why CalibAdc doesn't return the value expected. My tests, circumventing firmware, appear to return exactly what the firmware does, so it's not simply a case of "Rev-Ed got it wrong", there's something neither of us have got right or haven't realised. It's something Rev-Ed will have to look at.
 

MartinM57

Moderator
As it stands, it doesn't seem worth (me) bothering with CalibAdc(10) - I will have a good Vcc (7805-alike, hopefully with 0.1v = 2%) so will just trust ReadAdc(10) straight off.

Also, my PCB is destined for a vehicle and there will be a hardware- or software-initiated "calibrate" to taking the X, Y and Z readings from the accelerometer when parked on the level and treat these values as 0g, 0g and 1g respectively, to eliminate/correct any mounting errors.

I wouldn't have thought that the firmware for CalibAdc was particularly complex (ie is unlikely to be wrong) so I'm certainly interested what Technical have to say.....
 

hippy

Ex-Staff (retired)
I've currently got it marked down as a "Microchip Issue", either silicon error or failure to explain something clearly or correctly.
 

Technical

Technical Support
Staff member
The firmware correctly reports the PIC silicon register values, so our suspicion is the 0.6V quoted in the Microchip datasheet is a rounded value. A quick few bench tests here suggest 0.55V more closely matches real-life results.

so Hippy's formula
Vadc = ( Nadc * 6 / Nref ) / 10
becomes
Vadc = ( Nadc * 55 / Nref ) / 100
 

MartinM57

Moderator
That's pretty shocking to be honest :( ...and seems to vary across chips

Apart from those that (relatively) haven't got a clue about their supply voltage and are happy to use CalibAdc to get their ADC readings within 10%, then CalibAdc seems to be something to steer well clear of.

Is that a correct assumption?
 

BCJKiwi

Senior Member
Sorry Technical,
don't think its quite that simple
1. 0.55 vs 0.6 is an 8.3' % difference.
2. If it were a fixed variation, then all those who have posted here would have the same correction factor but,
3. Real world correction factors reported so far are 1.6%, 3.8% and 5.6% plus however you arrived at the 0.55 or 8.3%.
 

hippy

Ex-Staff (retired)
After a long search I found this, AN1072, "Measuring VDD Using the 0.6V Reference" -

http://ww1.microchip.com/downloads/en/AppNotes/01072A.pdf

For the 16F690 specifically but almost certainly applies to other PICmicro devices with an internal voltage reference. The crucial, revealing sentence ...

There is no way to know exactly what voltage the reference VP6 is before using the device. However, by performing a few calibrations, the value of the 0.6V reference can be removed from the measurement computation.

So, in a nutshell, that 0.6V voltage reference isn't a 0.6V voltage reference and it needs to be calibrated to be used ( details in AN1072 ). Better yet; the 'fixed reference' may alter as supply voltage and temperature changes so an average has to be used to minimise conversion error.

The first thing I did was download the latest 16F886/16F887 datasheet and look for the specification of VP6, but unless my eyes have failed me, I see nothing in the electrical specifications on it at all. No expected value range, no indication of supply or temperature effects.

As VP6 probably needs to be calibrated for each PICAXE device, the best solution for very accurate ADC conversion is to calibrate VP6 or use an external voltage reference with better stability than VP6. VP6 has a use, but it's not as useful as I thought it would be.
 

Technical

Technical Support
Staff member
Thanks for the link, we'd not seen that one before.
So basically the 0.6V quoted in the PIC datasheet may not be 0.6V at all. Microchips PIC datsheet is therefore very misleading!
 

BCJKiwi

Senior Member
In the 16F886/16F887 datasheet here is one reference to VP6 in the very last page where its gives a pointer to CVref.

A search in the datasheet for 0.6V turns up a number of references to the existence of the fixed reference voltage - just not called VP6 any more. The guts of the spec appears to be in section 8.10 if I've not gone off on a tangent.

There is also some discussion on VP6 in the errata sheet (page2, point 3) which may be relevant.
 

BCJKiwi

Senior Member
PLEASE REFER TO THE UPDATED (AND IMPROVED) ANALYSIS AND CODE SNIPPETS HERE;
http://www.picaxeforum.co.uk/showthread.php?p=57880#post57880
Thanks,
BCJ

Ran some further tests with varying supply, correction and no correction.

It turns out there are two different cases which should be treated differently;
1. The first where the sensor's voltage supply is regulated and independent of the PICAXE supply. Its analogue level will be independent of the PICAXE supply.

2. The other where the sensor behaves in some manner like a potentiometer and is supplied from the same supply as the PICAXE. In this case the analogue output voltage level of the sensor will change with the change in supply rail voltage for the same setting.

The first case requires no correction of ADC even if the PICAXE supply voltage changes.

The second case does require correction if the supply voltage changes.


CalibADC or a separate reference voltage could be used.
For the tests the following circuit, as suggested by Hippy, was used;
Code:
[COLOR=silver]   V+ ----/\/\/\/\----+----|>|---- V0[/COLOR]
[COLOR=silver]           R = 10k    |   BAT85[/COLOR]
[COLOR=silver]                      |[/COLOR]
[COLOR=silver]                      |[/COLOR]
[COLOR=silver]                     ADC[/COLOR]
[COLOR=silver]               Reference Voltage[/COLOR]
[COLOR=silver]   = 0.55V at all supply voltages 3.50 thru 5.00[/COLOR]
[COLOR=silver]     ReadADC10 here in place of CalibADC10[/COLOR]
The results for case 1 were as follows;
Code:
[COLOR=silver]Actual Supply Voltage (Bench supply)   5     4.5     4       3.5[/COLOR]
[COLOR=silver]Reference voltage          READADC10 114     125     139     156[/COLOR]
[COLOR=silver]supply  V+                 READADC10    1023    1023    1023    1023   [/COLOR]
[COLOR=silver]Y Axis Accelerometer       READADC10    340     380     427     488   [/COLOR]
[COLOR=silver]Voltages calculated using formula:- ReadADC10_V+ x 55 / ReadADC10_Reference /100[/COLOR]
[COLOR=silver]supply V+                               4.93    4.5     4.04    3.6   [/COLOR]
[COLOR=silver]Y Axis Accelerometer                    1.64    1.67    1.68    1.72   [/COLOR]
[COLOR=silver]Y Axis Accelerometer DMM measurement    1.67    1.68    1.68    1.68   [/COLOR]
[COLOR=silver]Y Axis Accelerometer from formula:- ReadADC10_YAxis / 1023 x V+[/COLOR]
[COLOR=silver]                                   1.662   1.672   1.67    1.670   [/COLOR]
[COLOR=silver]Y Axis Accelerometer without correction 1.6667  1.667   1.673   1.676[/COLOR]
This confirms that ReadADC is more accurate without correction than with correction for the sensor with an independent regulated supply. The accelerometer used in this test has it's own 3.3v internal regulator.

However for case two - resistor like sensor off the PICAXE supply, a different approach is required.

Without correction, the ReadADC value rises proportionately to the the fall in voltage (assuming the sensor has the same setting - i.e. if it were a potentiometer that was not moved).

To compensate for this a reference voltage is required. If the 28X1/40X1 chip is used then the calibADC could be used but see the discussion in the previous posts.
Alternatively a separate reference can be used - like the resistor / diode earlier in this post. this does use up an additional ADC port unless it is shared by using a relay to switch between sources.

A calibration reading would need to be taken of the voltage and the readadc10 value at that voltage at the highest end of the supply range - e.g. 5.00V & 114.

The calculation is easier to understand if separated into two parts;
A. correct the sensorADC reading for the change in supply voltage,
the formula for this using the values above is;
reference_ADC at reduced voltage - 114 x sensor_ADC
This scales the sensor ADC reading by the change in supply voltage.
B. Apply the scaled sensorADC reading to the same calculation used previously,
sensor_ADC at reduced voltage x 55 / ReadADC10_Reference /100
where 55 is the reference voltage X 100

This is the sensor circuit used for test - a simple voltage divider between the V+ and V0 rails.
Code:
[COLOR=silver]   V+ ----/\/\/\/\----+----/\/\/\/\---- V0[/COLOR]
[COLOR=silver]          R ~ 100k    |    R ~ 100k[/COLOR]
[COLOR=silver]                      |[/COLOR]
[COLOR=silver]                      |[/COLOR]
[COLOR=silver]                     ADC[/COLOR]
[COLOR=silver]               Voltage divider[/COLOR]
[COLOR=silver]   = 0.55V at all supply voltages 3.50 thru 5.00[/COLOR]
[COLOR=silver]     ReadADC10 here in place of Y Axis Accelerometer ReadADC above[/COLOR]
Test program
Code:
[COLOR=silver]#picaxe 28x1[/COLOR]
[COLOR=silver]SetFreq em16[/COLOR]
[COLOR=silver]#terminal 19200[/COLOR]
[COLOR=silver]'[/COLOR]
[COLOR=silver]symbol ADC_REF = 112    'Resistor/Diode Junction at 5.00 V[/COLOR]
[COLOR=silver]symbol ADC_CAL = w0      'Resistor/Diode Junction[/COLOR]
[COLOR=silver]symbol ADC_SEN = w2      'Sensor[/COLOR]
[COLOR=silver]pause 5000[/COLOR]
[COLOR=silver]'[/COLOR]
[COLOR=silver]READadc10 3,ADC_CAL     ' Resistor/Diode Junction[/COLOR]
[COLOR=silver]ReadADC10 1,ADC_SEN     ' Y Axis or voltage divider[/COLOR]
[COLOR=silver]sertxd("Calibration adc10 = ",#adc_cal,cr,lf)[/COLOR]
[COLOR=silver]sertxd("Sensor    readadc = ",#adc_sen,cr,lf)'b10,".",b11,b12,"V",CR,LF)   '[/COLOR]
[COLOR=silver]adc_sen = ADC_CAL/adc_ref*adc_sen ' 158/115*514 = 706.2[/COLOR]
[COLOR=silver]w8 = ADC_Sen * 56 / ADC_CAL    ' 706 * 56 / 158 = 250[/COLOR]
[COLOR=silver]b10= w8 DIG 2 +"0"[/COLOR]
[COLOR=silver]b11= w8 DIG 1 +"0"[/COLOR]
[COLOR=silver]b12= w8 DIG 0 +"0"[/COLOR]
[COLOR=silver]SerTxd ("Corrected voltage = ",b10,".",b11,b12,"V",CR,LF)'[/COLOR]
Sample results;
Code:
[COLOR=silver]Calibration adc10 = 113[/COLOR]
[COLOR=silver]Supply      adc10 = 0[/COLOR]
[COLOR=silver]Sensor    readadc = 513[/COLOR]
[COLOR=silver]Corrected voltage = 2.54V[/COLOR]
 
Last edited:

hippy

Ex-Staff (retired)
I cannot agree with your claim for (1), the self-powered sensor, that there's no need for ADC correction when PICAXE Vsupply changes; as PICAXE Vsupply drops the reading for the same sensor voltage will increase and reading will drop as Vsupply increases. I don't see how you're determining the first table's results "without correction".

For the second case ...

If the Vref is 0.55 and Vsupply is 5V then ReadAdc10 of Vref should return (0.55/5)*1023 = 112.53, 112 not the 114 you got. Likewise with Vsupply at 3.5V it should read 165 not the 156.

For the accelerometer Y-Axis, 1.67V should have read 341 not 340 at 5V, and 1.68V read as 491 not 488 at 3.5V.

I don't know why there are discrepancies between actual and theorised readings from ReadAdc10 but with over 6% error in them it's no surprise that using those readings in the final calculation gives result errors.

The question has to be, before all others, why are those readings in error ?
 

BCJKiwi

Senior Member
The first table's results 'without correction' were calcutated with a regular calculator as a sanity check.

As for the need for correction, it's all right here, using the PICAXE, without correction, you get the best result.
Code:
[/COLOR]
[COLOR=silver]Y Axis Accelerometer                    1.64    1.67    1.68    1.72   [/COLOR]
[COLOR=silver]Y Axis Accelerometer DMM measurement    1.67    1.68    1.68    1.68   [/COLOR]
[COLOR=silver]Y Axis Accelerometer from formula:- ReadADC10_YAxis / 1023 x V+[/COLOR]
[COLOR=silver]                                        1.662   1.672   1.67    1.670   [/COLOR]
[COLOR=silver]
Without correction you get the right answer - this is real world, not theory.

As for the accelerometer at 3.5v, these were the results returned. However the Accelrometer has an internal 3.3V reg which is fed from the main supply rail so since in that test it was only getting a 3.5V feed to the 3.3 Reg it may be out of spec. I did consider this when testing but did not pick up on the result as an error at the time.

As for the accuracy, I agree, even with ReadADC10, repeated readings of what one might expect to be the same value can move +-1 on the returned value - but then all this is being done on a breadboard.

I think what all this discussion shows is that the simplest answer and the best results would always be obtained by using a regulated supply to the entire system rather than trying to compensate for errors/offsets. When supply is from batteries, that may mean a higher voltage battery pack and efficient LDO regulator. It all comes down to what is needed for the application.
 
Last edited:

hippy

Ex-Staff (retired)
Maybe I'm just confused but, "Without correction you get the right answer - this is real world, not theory" ... how can you not be applying correction, as the Vsupply changes so too must the calculation, that is "the correction" ?
 
Top