Improved READINTERNALTEMP Routine(s).

AllyCat

Senior Member
Hi,

For me, READINTERNALTEMP is a most disappointing PICaxe command, although it must be said that this is partly due to the very "unfriendly" silicon (chip hardware) design of the "base" PICs, which makes any direct measurement highly sensistive to supply rail (Vdd) variations. I've already posted about this in several threads, e.g. this one, so here is my first formal description of an "improved" algorithm. I'm not posting it as a finished project yet because it's still a "work in progress" and I will be interested to hear if others can confirm the calibration factors employed.

To avoid a lengthy introduction, I'll assume some familiarity with the relevant section of PICaxe Manual 2, Microchip Application Note 1333 and at least posts #1 and #4 in this thread. However, it's worthwhile emphasising again that calibration (for at least one temperature point) is absolutely essential, because without this, the reported temperatures can span a range of literally hundreds of degrees.

To achieve good resolution (better than 1 degree C) and accuracy requires a detailed analysis of the supply voltage range and choice of parameters (2 or 4-diode sensor, etc.). However, the simplest arrangement happens to give reasonable results over the entire supply voltage range, so I'll start with that one here.

Unfortunately, an unresolved issue is that PE5 and PE6 (and AxePad 1.5.0 and 1.5.1) give different results for the "RAW" commands, so the Program needs conditional compilation (i.e. #IFDEFs), for the editor version employed. Thus either "USE_PE5" or "USE_PE6" should be #DEFINEd, but if not, the program uses a sequence of POKE/PEEK SFR commands which emulate the _RAW_ command for either editor:

The core calculation uses only 3 lines of program (starting at inttemp:) which employ four input parameters, but up to three of these can be constants defined within the program. The only essential variable is the voltage measured on the temperature-sensor diodes relative to "earth" (the zero or negative rail). The reason for using earth as reference is that for the higher resolution versions it's necessary to achieve better than 10 bits (1024 levels) resolution (which is all that can be obtained when the ADC is referenced to the Vdd rail).

Sadly, the base PIC Data Sheets and even Microchip AN1333 give little guidance on actual calibration values. AN1333 does specify the nominal temperature coefficient of the sensing diodes as -1.32 mV/C, but this only applies if an absolutely stable reference voltage is available. For the case of an autonomous routine (i.e. within the PICaxe), the only reference we have is the FVR (Fixed Voltage Reference) which itself has a significant tempco:

The base PIC data sheet for the 14/20M2 chips specifies the FVR tempco as -130 ppm, which equates to about -0.08 mV/C applied across the 600 mV forward drop of a typical diode. Thus the effective tempco falls to about -1.24 mV/diode, or only around 2.5 mV/C for the two-diode (Low Voltage) configuration. This is one reason why the temperature measurement is so sensitive to supply voltage variations.

FVRcharacteristtics.png

The primary improvement over the resident (PE6) calculation is to pass an EXACT supply rail voltage as a parameter to the temperature calculation routine. Typically, the value is in milliVolts (or even fractions of a mV) which may seem extreme, but is necessary to achieve reasonable accuracy. The value might be the designated stabilised external supply voltage, but normally will be a direct measurement of Vdd by a preliminary routine. This voltage is used twice, firstly to calibrate the ADC reference voltage steps and secondly to correct for the fact that the temperature-sensing diodes "hang down" from the supply rail (instead of being referenced directly to ground).

Next, the gradient of the temperature characteristic (degrees C per mV) is calculated by multiplying by a scale factor derived from the number of diodes and their tempco. Multiplication is used to attain a higher resolution/accuracy than PICaxe Basic's division can achieve. Normally, the scale factor can be a constant, unless a two-point calibration process is to be employed. Generally, one of two values will be used, depending whether the tempco is an absolute value (relative to a precision externally-generated Vdd), or relative to the internal FVR.

The final operation is to subtract from a "calibration constant", which extrapolates the temperature back from the point where the "forward diode drop" would be zero. Doing this subtraction last, permits a "one shot" calibration to accept a value directly in degrees (or tenths of a degree), and more significantly it delivers a result in twos-complement negative format, i.e. -1 degree is reported as 255 (byte) or 65535 (word). Additionally, an "offset zero" can be accommodated, for example -40 degrees (which is the same in C and F), as is often used in wireless temperature sender protocols, or even degrees Kelvin (Absolute) to ensure that negative values are not encountered. :)

With a Vdd of 5 volts, the ADC can resolve only in steps of 5 mV (i.e. equivalent to a resolution of 2 degrees), but worse, the single CALIBADC10 (and the necessary division stage) gives steps of 18 mV. These effects partially cancel each other, but (with an unstabilised Vdd) the simplest code version can resolve the temperature only down to a range of a few degrees Centigrade, even after calibration.

So here is the basic version of my modified algorithm which in its pre-defined Vdd version uses less program space than each resident "IT_xVx" command in PE6. The "#define MIN_CODE" selects a basic CALIBADC10 measurement to give 18 mV resolution, otherwise a nominal "9 mV resolution" is selected at the expense of about an extra 12 bytes of code. The simplest Vdd-measuring PE5 version uses a total of around 40 bytes, the "SFR" version just over 50 and PE6 slightly more.

Code:
; Basic READINTERNALTEMP for any supply voltage using PE5 or PE6
; AllyCat November 2015

#no_data		
#terminal 4800		
;#define USE_PE5				; Compensates for code bugs in PE5 editor (and AxePad < 1.5.1)
;#define USE_PE6				; If neither editor is selected then uses SFR commands 
;#define MIN_CODE				; Minimumise code size (lower Vdd measurment accuracy)
	
symbol TEMPCO = 124              		; Temperature coefficient of one diode (mV/deg C * 100)
symbol ZERO_VD = 538		   	; Extrapolated temperature for zero diode drop (C)
symbol CAL_VDD18 = 58254			; Calibration factor for 18 mV steps (nominally 1024 * 1024 / 18)
symbol SCALE2D = 3276800 / TEMPCO		; Nominal slope calibration = 65536 / 2 diodes (mV)	

do
	calibadc10 w2
#ifdef MIN_CODE	
	w1 = CAL_VDD18 / w2 * 18		; Supply voltage in mV (18 mV steps)
;	w1 = 4000			; Alternative for a 4 volt stabilised supply
#else										
 	calibadc10 w1  
	w2 = w1 / 2 + CAL_VDD18 / w1	; Round up by half divisor and calculate supply voltage / 18
	calibadc10 w1			; Read again to average noise
	w1 = CAL_VDD18 / w1 + w2 * 9	; Supply voltage in mV (9 mV steps)
#endif	; /MIN_CODE

readintemp:				; Read Internal Tempeature with Vdd (mV) in w1
#ifdef USE_PE5
	readinternaltemp IT_RAW_H,0,w2	; Reads 2 diodes ref Vdd (PE5 bug has _L and _H swapped)
#else      
#ifdef USE_PE6                 
	readinternaltemp IT_RAW_L,0,w2	; Reads 2 diodes ref Vdd (~1100 mV @ 25C) ~2.5 mV/C
#else					; Read voltage using SFR accesses
	symbol ADRESL 	= $3B		; ADC Low byte
	symbol ADRESH 	= $3C		; ADC High byte
	symbol ADCON0 	= $3D		; ADC control register 0
	symbol ADCON1	= $3E		; ADC control register 1
	symbol FVRCON 	= $57		; En=80,TmpEn=20,TmpHi/Lo=10,DAC=0C,ADC=03(off/1/2/4volts)
	pokesfr FVRCON, %10101010   	; Enable Temperature sensor with 2 diodes and FVR = 2
	pokesfr ADCON1, %10010000	; Right justify; clock/8; REF=Vdd     
	pokesfr ADCON0, %01110101 	; Select Temperature input and Turn ADC On
	pokesfr ADCON0, %01110111 	; Start conversion
	peeksfr ADRESL,b4,b5 		; Read lower and upper bytes into w2
#endif ; /USE_PE6
#endif ; /USE_PE5
inttemp:				; Start of main algorithm
  	w2 = w2 * 64 ** w1		; ADC steps * mV/step (Vdd/1024 = Vdd ** 64) = mV
  	w2 = w1 - w2 ** SCALE2D		; mV across 2 diodes, scaled down to unit degrees
 	w2 = ZERO_VD - w2		; Temperature in degrees C
	sertxd(#w1," mV ",#w2," C",cr,lf)	; Report Vdd and Internal Temperature
	pause 3000
loop
This post is nearing the forum's 10,000 characters limit so I will need to show the measured performance details in a subsequent post. However, I have already included a "Medium Resolution" version of the algorithm in this finished project and hope to post a "Higher Resolution" version in due course. However, one of the remaining issues is how to manage the numerous permutations of supply voltage range, resolution, display format (C/F and "decimal" part, etc.) and PE5/PE6/AxePad/SFR versions, etc. in a reasonably comprehensible way. ;)

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

The 10,000 character forum post limit didn't allow me to include practical measurements of the algorithm above, so here they are now. The graphs were created using a spreadsheet program and the "Vdd sweeper" hardware and software described in this recent finished project.

The graph below shows the typical performance (Vertical Axis = degrees C) of a 20M2 operating between 1.6 and 5 volts (Horizontal Axis in mV), using the "9" and "18" mV versions of the code. These are compared with the resident READINTERNALTEMP IT_3V5,50,W1 , which was limited at 0C and 40C to retain a useful vertical scale. A graph of the complete range of the resident READINTERNALTEMP (PE6) routines was shown in this thread.

MinReadinternalTemp.png

Each "line" in the graph contains over 1500 points so the width of the lines can be considered as a reasonable limit (max-min) error spread. The "18 mV" (Yellow) line is mainly hidden behind the "9 mV" line (Red) so is repeated 10 degrees C higher (Green). Below about 3 volts, there is a significant difference, but at higher voltages the advantage is rather small, probably due to noise inside the PICaxe.

A simple "rolling average" might produce a more stable output, but the noise seems to be of rather low frequency (perhaps it's partly the quantising errors of PICaxe's integer calculations when the Vdd slews), so the improvement seemed rather less than might be expected. However, even the full width of the lines corresponds to only around a 40 mV error in the specified supply rail of the resident "defined Vdd" version (Blue).

It's perhaps worth considering here, at what supply voltage the four diode sensor can be used; the PICaxe Manual pessimistically suggests only above 4 volts and the base PIC data sheet greater than 3.6 volts for 4 diodes and 1.8 volts for two.

AN1333 says that the forward voltage drop of each diode may be up to 750 mV which suggests (with the 1.8 volts from the data sheet) that the current source may need 300 mV of "headroom", so 3.3 volts seems more consistent for 4 diodes. Also, the 750 mV per diode applies at -40 degrees C, so in practice it may be reasonable to assume a minimum drop across four diodes plus the current source of only a little above 3 volts. Thus the 4 diode version might be usable with a Lithium Phosphate (LiFePO4) rechargeable cell, but certainly NOT with a pair of AA alkaline or NiMH cells.

Cheers, Alan.
 

erco

Senior Member
More incredible work, AllyCat. Thanks for sharing your knowledge. I'll have to go over this in detail when I can.

10,000 characters? Wow, where do you get the time & energy?
 

tmfkam

Senior Member
Wow.

Really appreciate that.

I was trying at one point to track the internal temperature relative to the accuracy (or otherwise) of the internal 'Time' variable. Something like this would have been really useful.

Many thanks for sharing your hard work.
 
Top