#define ZERO_DEGC_IN_CENTIK 27315ul // centi-K = 0.01K units
struct {
// alpha numerator and denominator
uint16_t alphan; // ADC bits
int32_t alphad; // 0.01K units
} calibration;
/*
* Initialize module
* 89.5F (31.9C) = alphan 293
*/
void inttemp_init(void)
{
// arbitrary values
calibration.alphan = 293;
calibration.alphad = 319 * 10 + ZERO_DEGC_IN_CENTIK;
}
/*
* 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);
}
...
/*
* use the CTMU to measure the internal temp diode and return a voltage
* It's only good for about +- 1.0C resolution at best but it will work
* for time measurement calibration drift
*/
uint16_t measure_chip_temp(uint8_t mode)
{
L.ctmu_data = LOW;
L.ctmu_data_temp = HIGH;
ADCON1bits.VCFG = 2; // Vref+ = 2.048
ADCON0bits.CHS = TEMP_DIODE; // Select ADC channel
CTMUCONHbits.CTMUEN = LOW;
if (mode) {
CTMUICON = 0b01111111; // 55uA CC max trim +62%
} else {
CTMUICON = 0b01111110; // 5.5uA CC max trim +62%
}
CTMUCONHbits.CTMUEN = HIGH;
CTMUCONHbits.IDISSEN = LOW; // end drain
PIE3bits.CTMUIE = LOW; // don't generate CTMU interrupts for edges
CTMUCONLbits.EDG1STAT = 0; // Set Edge status bits to zero
CTMUCONLbits.EDG2STAT = 0;
CTMUCONLbits.EDG1STAT = 1; // start current source
wdtdelay(20); // CTMU setup time before sampling
ADCON0bits.GO = 1; // Start conversion
wdtdelay(20); // wait for ISR to update buffer
CTMUCONLbits.EDG1STAT = 0; // deactivate current source
CTMUICON = 0x00; // current off
return L.pic_temp;
}
/*
* Measure delta voltage across internal diode at two currents.
*/
uint16_t inttemp_deltav(void)
{
uint16_t v1, v2;
v1 = (uint16_t) lp_filter((float) measure_chip_temp(LOW), 1, HIGH);
v2 = (uint16_t) lp_filter((float) measure_chip_temp(HIGH), 2, HIGH);
return v2 - v1;
}
/*
* Read current internal temperature in 0.1C
*/
int16_t inttemp_read(void)
{
// temperature = delta diode voltage * (1 / alpha)
return((int32_t) inttemp_deltav() * (int32_t) calibration.alphad / (int32_t) calibration.alphan - ZERO_DEGC_IN_CENTIK) / 10;
}