Here is my first formal description of an algorithm to accurately calculate the PICaxe's Chip Temperature using only the available on-chip hardware. It's presented as a subroutine within a test harness, for compatibility with PE5, but equally it might be wrtten as a macro and/or embedded within a larger program/subroutine. I've written much on the READINTERNALTEMP commands, for example the

__bugs__(in PE5) and

__voltage sensitivity__, etc., so here I will deal only with a calculation method for the chip temperature using "available" commands.

The complete temperature-measurement process can be divided into four stages:

**1.**ADC measurement(s) of the supply rail voltage (Vdd),

**2.**ADC measurement(s) of the on-chip temperature-sensing diodes,

**3.**Calculation of the temperature (gradient) in the desired units, and

**4.**Post-processing the result for calibration, filtering and display, etc..

I've already posted several code snippetts to measure the supply rail (e.g. for "

__10mV__" and "

__1mV__" resolution) and written much on the READINTERNALTEMP command. So I won't expand on the options here, but just include a compatible (PE5/PE6) bug-fixed version. Similarly, there are numerous possibilities for post-processing, for example averaging (to reduce spikes or noise), formatting in integer degrees C or F, etc., or even to one decimal place of resolution. Then display the result on the PE terminal (SERTXD..) , on a LCD (SEROUT..) or even via

__PWM to a DVM__, so only a few examples can be shown here.

The algorithm may be optimised for any particular application, but here are just two versions; a basic CHIPTEMP routine and a higher resolution CHIPTEMP10 (named similarly to other PICaxe keywords). However, in this case the "10" suffix indicates that the integer result can be 10 times larger (and thus converted to a "one decimal place" result).

The basic calculation requires two fundamental input parameters, i.e. :

**a.**The Supply Rail Voltage and

**b.**A Temperature-related Voltage measurement (from 1. and 2. above).

Also, the temperature coefficient of the on-chip diodes is required (e.g. from a two-point calibration), but in most cases this can be a fixed constant (typically 1.24 mV/degree C for each diode). The algorithm also needs a few "switches", to indicate the number of diodes being used and the number of individual ADC measurements, etc., which are defined by additional program constants.

Last, but definitely not least, the temperature

__MUST__be calibrated for every individual target chip. This is intentionally the last stage in the calculation, which ensures that the calibration is applied directly in integer degrees (or tenths in the case of the "decimal" version). Thus, a single calibration operation is sufficient: The first time the program is run, simply subtract the reported temperature from the actual (room) temperature and apply the numerical value directly to the appropriate "calibration constant", ITZ{10} , within the program.

So here are the two subroutines, with a test harness to demonstrate the integer and decimal versions, and also report the measured supply voltage, on the PE terminal emulator. The raw calculation consists of just three assignments which can be written in three lines of code, however the "10" version is spread over five lines, to accommodate more detailed comments. :

Code:

```
; CHIPTEMP{10} : A calculation algorithm for the internal chip temperature of M2 PICAXEs.
; AllyCat, February 2016.
#picaxe 20m2
#no_data
#terminal 4800
; Variables:
symbol tempb = b1 ; Temporary/Local Byte, also for passing paramters etc.
symbol tempw = w1 ; Temporary/Local Word, also for passing paramters, etc
symbol Vdd = w2 ; PICAXE supply rail voltage in mV
symbol Vadd = w3 ; Additional Word variable, sometimes needed for local calculations
; Calibration Constants:
symbol ITZ10 = 5100 ; Calibration offset temperature value in tenths of a degree C
symbol CALVDD20 = 52429 ; Calibrate Vdd, nominally 1024 (ADC steps) * 1024 (FVR mV) / 20 (stepsize mV)
symbol CALVDD7 = 59919 ; Adjust to calibrate Vdd, nominally 65536 * 32 / 5 / 7 (used in ReadVdd2)
symbol TEMPCO = 124 ; Temperature coefficient of one internal diode (mV/C * 100)
symbol DEMO = 2 ; Multiplier to allow decimal resolution to be demonstrated (otherwise = 1)
; Constants for CHIPTEMP10 version (Can give decimal result)
symbol NVDD10 = 2 * DEMO ; Number of times Vdd is included (i.e. number of READINTERNALTEMPs)
symbol GRAD12 = 5461333 / TEMPCO ; Voltage / Temperature conversion factor for 12 diodes (655360/12)
symbol SLOPE10 = GRAD12 ; Calibration Constant to convert mV into degrees (Fractional value * 65536)
; Constants for CHIPTEMP (integer result) version:
symbol NVDD = 2 ; Number of times Vdd is included (i.e. number of READINTERNALTEMPs)
symbol ITZ = ITZ10 / 10 ; Calibration temperature corresponding to zero diode voltage (C)
symbol GRAD6 = 1092267 / TEMPCO ; Voltage / Temperature conversion factor for 6 diodes (65536/6)
symbol SLOPE = GRAD6 ; Calibration Constant to convert mV into degrees (Fractional value * 65536)
main:
do
; First measure the basic Vdd and Raw Chip Temperature voltages:
call ReadVdd ; Get normal supply voltage in mV
readinternaltemp IT_RAW_H,0,Vadd ; ADC value (steps) for 4 diodes (2 diodes with PE5)
fvrsetup %10111010 ; Bugfix for PE5 (selects 4 diodes)
readinternaltemp IT_RAW_L,0,tempw ; ADC value for 2 diodes (4 diodes with PE5)
tempw = tempw + Vadd ; ADC value for 6 diodes (with 2 * Vdd measurements)
Vadd = tempw ; Save value to use with CHIPTEMP10 routine later
; Now the basic integer calculation:
call ChipTemp ; Input parameters in tempw & Vdd, result in tempw (or b2)
sertxd(cr,lf,#tempw,"C ") ; Report the basic integer calculation (CHIPTEMP)
; Now the "High Resolution" version:
call ReadVdd2 ; Higher accuracy measurement of Vdd (in mV)
sertxd("Vdd= ",#Vdd,"mV ") ; Report the supply voltage
tempw = Vadd * DEMO ; Recover value and Multipy to demonstrate decimal result
Vadd = 0 ; Zero unless a FVR was used as an ADC reference voltage
call ChipTemp10 ; Input parameters in tempw,Vdd (& Vadd),result in tempw
; Split the result into decimal parts and report:
tempb = tempw // 10 ; Decimal part of result
tempw = tempw / 10 ; Integer part of result
sertxd(#tempw,".",#tempb,"C") ; Report the temperature in degrees C
pause 3000
loop
ChipTemp10: ; Generic Chip Temperature calculation
tempw = tempw * 16 ** Vdd ; Number of ADC steps * Vdd (stepsize) / 4.(Max 4 * ADC values)
tempw = tempw * 2 + Vadd * 2 ; Add the ADC steps referenced to FVR2048 (= mV/2) and double
tempw = Vdd * NVDD10 - tempw ; Subtract from sum of Vdds
tempw = tempw ** SLOPE10 ; Scale to degrees (or degrees * 10)
tempw = ITZ10 - tempw ; Calibrate to reference temperature (e.g. zero C)
return ; Returns tempw = deg C * 10 (if appropriate constants are used)
ChipTemp:
tempw = tempw * 16 ** Vdd * 4 ; Number of ADC steps * Vdd (stepsize), Max 4 * ADC values.
tempw = Vdd * NVDD - tempw ** SLOPE ; Subtract from number of Vdds and Scale to degrees
tempw = ITZ - tempw ; Calibrate to reference temperature (0C;-40C;-273C,etc.)
return ; Returns tempw = deg C (or as calibrated)
ReadVdd:
adcconfig 0 ; Bugfix (omission from CALIBADC) if ADC has been referenced by FVR
calibadc10 tempw ; Measure FVR1024 relative to Vdd
Vdd = CALVDD20 / tempw * 20 ; Calculate the Vdd in mV
Vdd = Vdd + 20 ; Round up the constant to make integer/decimal results more consistent
return
ReadVdd2:
fvrsetup fvr2048 ; Will be used as ADC reference voltage
dacsetup $80 ; Enable DAC with Vdd reference
daclevel 10 ; Highest to accommodate Vdd = 6v (if FVR = 2048)
Vdd = 0 ; Prepare to accumulate the Vdd measurement
for b1 = 1 to 7 ; 7 x samples allows ** to calibrate up to 6000 mV result
adcconfig 3 ; FVR reference for ADC
readdac10 tempw ; Note this command uses DAC (not ADC)
Vdd = Vdd + tempw ; Accumulate scaled Vdd = loops * 1024 * 5 * Vdd / 32
next b1
Vdd = Vdd ** CALVDD7 ; Calibrate to mV units (multiplier < 1 )
return
```

Cheers, Alan.