This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR6989: Internal temperature sensor accuracy

Other Parts Discussed in Thread: MSP430FR6989

Hi,

I have a trouble with the internal  temperature sensor. The code is the example included in the driverLib:

// MSP430FR69xx Demo - ADC12_B, Sample A10 Temp and Convert to oC and oF
//
// Description: A single sample is made on A10 with internal reference voltage
// 1.2V. Software manually sets ADC12SC to start sample and conversion and
// automatically cleared at EOC. It uses ADC12OSC to convert the sameple.
// The Mainloop sleeps the MSP430 in LPM4 to save power until ADC conversion
// is completed. ADC12_ISR forces exit from LPMx in on exit from interrupt
// handler so that the mainloop can execute and calculate oC and oF.
// ACLK = n/a, MCLK = SMCLK = default DCO ~ 1.045MHz, ADC12CLK = ADC12OSC
//
// Un-calibrated temperature measured from device to device will vary due to
// slope and offset variance from device to device - please see datasheet.
// Note: This example uses the TLV calibrated temperature to calculate
// the temperature
// (the TLV CALIBRATED DATA IS STORED IN THE INFORMATION SEGMENT, SEE DEVICE DATASHEET)
//
//               MSP430FR6989
//             -----------------
//         /|\|             XIN|-
//         | |                 |
//         --|RST         XOUT|-
//           |                 |
//           |A10              |
//
//   William Goh
//   Texas Instruments Inc.
//   April 2014
//   Built with IAR Embedded Workbench V5.60 & Code Composer Studio V6.0
//******************************************************************************
#include <msp430.h>

#define CALADC12_12V_30C *((unsigned int *)0x1A1A)   // Temperature Sensor Calibration-30 C
                                                     //See device datasheet for TLV table memory mapping
#define CALADC12_12V_85C *((unsigned int *)0x1A1C)   // Temperature Sensor Calibration-85 C

unsigned int temp;
volatile float temperatureDegC;
volatile float temperatureDegF;

int main(void)
{
WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

// Initialize the shared reference module
// By default, REFMSTR=1 => REFCTL is used to configure the internal reference
while(REFCTL0 & REFGENBUSY);             // If ref generator busy, WAIT
REFCTL0 |= REFVSEL_0 + REFON;             // Enable internal 1.2V reference

/* Initialize ADC12_A */
ADC12CTL0 &= ~ADC12ENC;                   // Disable ADC12
ADC12CTL0 = ADC12SHT0_8 + ADC12ON;       // Set sample time
ADC12CTL1 = ADC12SHP;                     // Enable sample timer
ADC12CTL3 = ADC12TCMAP;                   // Enable internal temperature sensor
ADC12MCTL0 = ADC12VRSEL_1 + ADC12INCH_30; // ADC input ch A30 => temp sense
ADC12IER0 = 0x001;                       // ADC_IFG upon conv result-ADCMEMO

while(!(REFCTL0 & REFGENRDY));           // Wait for reference generator
                                            // to settle
ADC12CTL0 |= ADC12ENC;

while(1)
{
   ADC12CTL0 |= ADC12SC;                   // Sampling and conversion start

   __bis_SR_register(LPM0_bits + GIE);     // LPM4 with interrupts enabled
   __no_operation();

   // Temperature in Celsius. See the Device Descriptor Table section in the
   // System Resets, Interrupts, and Operating Modes, System Control Module
   // chapter in the device user's guide for background information on the
   // used formula.
   temperatureDegC = (float)(((long)temp - CALADC12_12V_30C) * (85 - 30)) /
           (CALADC12_12V_85C - CALADC12_12V_30C) + 30.0f;

   // Temperature in Fahrenheit Tf = (9/5)*Tc + 32
   temperatureDegF = temperatureDegC * 9.0f / 5.0f + 32.0f;

   __no_operation();                       // SET BREAKPOINT HERE
}
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))
{
   case ADC12IV_NONE:       break;       // Vector 0: No interrupt
   case ADC12IV_ADC12OVIFG: break;       // Vector 2: ADC12MEMx Overflow
   case ADC12IV_ADC12TOVIFG: break;       // Vector 4: Conversion time overflow
   case ADC12IV_ADC12HIIFG: break;       // Vector 6: ADC12BHI
   case ADC12IV_ADC12LOIFG: break;       // Vector 8: ADC12BLO
   case ADC12IV_ADC12INIFG: break;       // Vector 10: ADC12BIN
   case ADC12IV_ADC12IFG0:                 // Vector 12: ADC12MEM0 Interrupt
     temp = ADC12MEM0;                     // Move results, IFG is cleared
     __bic_SR_register_on_exit(LPM4_bits); // Exit active CPU
     break;
   case ADC12IV_ADC12IFG1:   break;       // Vector 14: ADC12MEM1
   case ADC12IV_ADC12IFG2:   break;       // Vector 16: ADC12MEM2
   case ADC12IV_ADC12IFG3:   break;       // Vector 18: ADC12MEM3
   case ADC12IV_ADC12IFG4:   break;       // Vector 20: ADC12MEM4
   case ADC12IV_ADC12IFG5:   break;       // Vector 22: ADC12MEM5
   case ADC12IV_ADC12IFG6:   break;       // Vector 24: ADC12MEM6
   case ADC12IV_ADC12IFG7:   break;       // Vector 26: ADC12MEM7
   case ADC12IV_ADC12IFG8:   break;       // Vector 28: ADC12MEM8
   case ADC12IV_ADC12IFG9:   break;       // Vector 30: ADC12MEM9
   case ADC12IV_ADC12IFG10: break;       // Vector 32: ADC12MEM10
   case ADC12IV_ADC12IFG11: break;       // Vector 34: ADC12MEM11
   case ADC12IV_ADC12IFG12: break;       // Vector 36: ADC12MEM12
   case ADC12IV_ADC12IFG13: break;       // Vector 38: ADC12MEM13
   case ADC12IV_ADC12IFG14: break;       // Vector 40: ADC12MEM14
   case ADC12IV_ADC12IFG15: break;       // Vector 42: ADC12MEM15
   case ADC12IV_ADC12IFG16: break;       // Vector 44: ADC12MEM16
   case ADC12IV_ADC12IFG17: break;       // Vector 46: ADC12MEM17
   case ADC12IV_ADC12IFG18: break;       // Vector 48: ADC12MEM18
   case ADC12IV_ADC12IFG19: break;       // Vector 50: ADC12MEM19
   case ADC12IV_ADC12IFG20: break;       // Vector 52: ADC12MEM20
   case ADC12IV_ADC12IFG21: break;       // Vector 54: ADC12MEM21
   case ADC12IV_ADC12IFG22: break;      // Vector 56: ADC12MEM22
   case ADC12IV_ADC12IFG23: break;       // Vector 58: ADC12MEM23
   case ADC12IV_ADC12IFG24: break;       // Vector 60: ADC12MEM24
   case ADC12IV_ADC12IFG25: break;       // Vector 62: ADC12MEM25
   case ADC12IV_ADC12IFG26: break;       // Vector 64: ADC12MEM26
   case ADC12IV_ADC12IFG27: break;       // Vector 66: ADC12MEM27
   case ADC12IV_ADC12IFG28: break;       // Vector 68: ADC12MEM28
   case ADC12IV_ADC12IFG29: break;       // Vector 70: ADC12MEM29
   case ADC12IV_ADC12IFG30: break;       // Vector 72: ADC12MEM30
   case ADC12IV_ADC12IFG31: break;       // Vector 74: ADC12MEM31
   case ADC12IV_ADC12RDYIFG: break;       // Vector 76: ADC12RDY
   default: break;
}
}
 

The reference is 1.2V and the temperature seems calibrated. In debug phase we check the variable VALUE and repeating the single acquisition, we observe that there is a variation in the temperature value up to 5C. Is this the accuracy of the sensor? In this case it seems very poor.

 Or there are some code errors. Are there other examples (correct)?

Thank you

Warm regard.


 

  • I forgot to say that we are using the eval board, powered by FET flash emulation tool (JTAG). I suspect that the calibration is not the point. Is it the noise of the power supply? Is it necessary a SW filtration of the data?
  • Hi,

    it is not clear to me how to implement the calibration of the ADC. I'm working with internal Vref.

    1) There is the calibration of Vref

    2) than the calibration of GAin and Offset of ADC.

    - both have to be implemented?

    - how to do this job? Is there a formula considering both corrections? (in data sheet I found one formula for Vref and one for gain-offset).

    - has the Vref calibration to be applied also to temperature sensor?

  • The temperature sensor is not that good. If I remember correctly, it can have a deviation up to 30K and even with the calibration values it is up to 3K. But of course this is an offset that will not change in two consecutive readings. So hard to say what could be the reason in your specific case. Try some filtering. A moving average might be sufficient.
  • Hi Alessandro,

    The 1.2 V reference calibration is stored at 1A28h of the TLV and can be used to adjust a raw ADC reading using the equation ADC(VREF_calibrated) = ADC(raw)*CAL_ADC12VREF_FACTOR/32768. This is not implemented in your code.

    ADC offset and gain calibration are stored at 01A6h and 01A8h of the TLV, respectively. They are used to further correct the ADC value using the equation ADC(final) = ADC(VREF_calibrated)*(CAL_ADC_GAIN_FACTOR/32768)+CAL_ADC_OFFSET. This also is not done inside of your code.

    The temperature sensor references are stored at 1A1Ah and 1A1Ch of the TLV for 30 and 80 degrees Celsius, respectively. These calibration values take into account CAL_ADC12VREF_FACTOR, CAL_ADC_GAIN_FACTOR, and CAL_ADC_OFFSET which is why they are not referenced by the example code. The equation using the temp sensor calibration becomes Temp [C] = (ADC(raw)-CAL_ADC_12T30)*(55/(CAL_ADC_12T85-CAL_ADC_12T30))+30, which is currently implemented by the code.

    If using the internal temperature sensor, CAL_ADC_12T30 and CAL_ADC_12T85 are used but a (+/-) 3 degrees Celsius error should be expected due to the nature of the sensor. If using an external temperature sensor for higher accuracy, CAL_ADC12VREF_FACTOR, CAL_ADC_GAIN_FACTOR, and CAL_ADC_OFFSET are used.

    Regards,
    Ryan
  • Hi,

    The sensor is not very good , but I expected a constant error. For each acquisition the result is different. So there are 2 explanations:

    - There is a big noise on internal ADC.

    - The calibration is repeated continuously with different results or the calibration process doesn't work very well.

    Thank you.

    Best regards.

  • Alessandro,

    Noise on the internal ADC can be created by fluctuations in the AVcc supply, please ensure that it is as steady as possible. The calibration constant provided in the TLV never changes but the actual equation that uses it, as shown by the code provided, repeats to calculate each sample.

    Regards,
    Ryan

**Attention** This is a public forum