CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to

Temperature sensor with internal diode and CTMU

Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message

Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

Temperature sensor with internal diode and CTMU
PostPosted: Sat Mar 16, 2013 11:31 pm     Reply with quote

For a recent project involving a PIC18F67K22, I investigated the use of the internal diode as a temperature sensor in combination with the CTMU peripheral. Microchip say it can be done, but with no guidance on the sort of accuracy possible. You only find out by doing, I guess!

Code follows, but in short, at the very best you should only expect a temperature resolution of about 1.7-1.8 degC. In practice something like +/- 3.6 degC or even +/- 7 degC would be expected.

It would be usable for a general "too hot" or "too cold" type sensor, but I wanted something a little more precise (+/- 1 degC) so I'm going with an external sensor.

I know other people will be tempted, like me, to see what the built-in temperature sensor is like. Here's the code to find out!

Exclamation The implementation of adc_read() is left as an exercise for the reader Smile

#ifndef INTTEMP_H
#define INTTEMP_H

#include <stdint.h>


// Initialise the internal temperature module
void inttemp_init(void);

// Perform a single point calibration using a known correct current temperature
void inttemp_calibrate(int16_t temperature); // 0.1degC units

// Load/save calibration
void inttemp_load_calibration(uint8_t *cal);
void inttemp_save_calibration(uint8_t *cal);

// Read the internal temperature sensor
int16_t inttemp_read(void); // 0.1degC units

#endif /* INTTEMP_H */

#include "inttemp.h"

#pragma module



* SBAA073A "Measuring Temperature with the ADS1216, ADS1217, or ADS1218"
* DS39660D "PIC18F87K22 Family, 27.8 Measuring Temperature with the CTMU Module"
* TB3016 "Using the PIC MCU CTMU for Temperature Measurement"
* AN1375 "See What You Can Do with the CTMU"

In short, taking diode voltage measurements using two different currents
eliminates all the device specific variables (such as the +/-60% CTMU current
accuracy, and variations with temperature). Calibration can then be performed
via a single measurement.

From SBAA073A:

delta diode voltage = alpha * temperature

where alpha is a constant made up of various physical constants and the ratio of
the excitation currents, the temperature is in Kelvin

For calibration:

alpha = delta diode voltage / temperature

For calibrated temperature:

temperature = delta diode voltage / alpha = delta diode voltage * (1 / alpha)

Worked example:

Assume temperature is 290 (29.0 degC), v1=998, v2=827, dv=171
alphan = 171 bits = 0.138V (Vref+=3.3V,Vref-=0V)
alphad = 30215 (0.01K units)
alpha = 2189 K/V = 1.767 K/bit

Normally +/- 1 ADC bits is pretty good, but we're reading twice, so the expected
error is actually more like +/- 2 bits, which is +/-3.5 K.


#byte CTMUICON = getenv("SFR:CTMUICON")
#bit CTMUEN = getenv("BIT:CTMUEN")
#bit EDG1STAT = getenv("BIT:EDG1STAT")
#define ZERO_DEGC_IN_CENTIK 27315 // centi-K = 0.01K units

struct {
  // alpha numerator and denominator
  uint16_t alphan; // ADC bits
  int32_t alphad; // 0.01K units
} calibration;
#if sizeof(calibration) != INTTEMP_CALIBRATION_SIZE
#error Inconsistent calibration size

// Initialise module
void inttemp_init(void)
  // arbitrary values
  calibration.alphan = 171;
  calibration.alphad = 290 * 10 + ZERO_DEGC_IN_CENTIK;

// Measure delta voltage across internal diode at two currents.
static uint16_t inttemp_deltav(void)
  uint16_t v1, v2;
  CTMUICON = 0x03; // 100x base current, 55uA
  CTMUEN = 1; // enable CTMU
  EDG1STAT = 1; // ADC output
  v1 = adc_read(ADC_CHANNEL_DIODE);
  EDG1STAT = 0; // disable output
  CTMUEN = 0; // disable CTMU
  CTMUICON = 0x02; // 10x base current, 5.5uA
  CTMUEN = 1;
  EDG1STAT = 1;
  v2 = adc_read(ADC_CHANNEL_DIODE);
  EDG1STAT = 0;
  CTMUEN = 0;
  CTMUICON = 0x00; // current source disabled
  // v1 will always be > v2 due to higher current
  return v1 - v2;

// Single point calibration to assumed ambient temperature
void inttemp_calibrate(int16_t temperature)
  // alpha = delta diode voltage / temperature
  calibration.alphan = inttemp_deltav();
  calibration.alphad = ((int32_t)temperature * 10 + ZERO_DEGC_IN_CENTIK);

// Load a saved calibration
void inttemp_load_calibration(uint8_t *cal)
  memcpy(&calibration, cal, INTTEMP_CALIBRATION_SIZE);

// Save the calibration
void inttemp_save_calibration(uint8_t *cal)
  memcpy(cal, &calibration, INTTEMP_CALIBRATION_SIZE);

// Read current internal temperature
int16_t inttemp_read(void)
  // temperature = delta diode voltage * (1 / alpha)
  return ((int32_t)inttemp_deltav() * calibration.alphad / calibration.alphan - ZERO_DEGC_IN_CENTIK) / 10;

Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group