[原创] TI MSPM0L1306 LaunchPad体验08:内部温度传感器出厂校准误差有200多摄氏度?

x1816   2023-11-7 11:04 楼主

 

尝试用MSPM0L1306芯片内部温度传感器测量温度,并和外置的热敏电阻读数对比。
热敏电阻的温度换算,在 TI MSPM0L1306 LaunchPad体验05:使用ADC采集热敏电阻信号并换算成温度中已经实现。本文重点关注内部温度传感器的使用。

内部温度传感器

阅读MSPL01306 datasheet,发现内部温度传感器有一个出厂标定的温度,为30摄氏度,温度系数TSc为-1.75e-3。
105636ehajha9quppu88hz.png
阅读MSPM0L系列Technical Reference Manual,里面详细介绍了adc码值转换为温度的公式,基本思路是器件温度和输出的电压是线性关系,温度系数是负值,因此温度越高,电压越低。
另外还需要一个参考温度点,来标定关系曲线的截距。
105636m7g3xgm6zbnhzbn5.png
105636mnz40dada9q6ujgw.png
这个标定的温度点对应的ADC码值,就是TEMP_SENSE0。
TEMP_SENSE0存储在每个器件的内部。获取TEMP_SENSE0常量,可以查阅driverlib文档的Factory Region (FACTORYREGION)部分,找到对应的函数:
105636mbz55rb2bscv22rp.png
一行搞定:
volatile const uint32_t TEMP_SENSE0 = DL_FactoryRegion_getTemperatureVoltage();

 

我手上的板子,TEMP_SENSE0的值为377。
105636g3qqxug193c4gggo.png
注意:此处似乎有坑,请看下文。

SysConfig配置

ADC12
105636rpec9yhh36p9bk84.png
2个通道分别采样外部热敏电阻电压和内部温度传感器电压。
注意Reference不一样,外部是3.3V左右的VDDA,内部用1.4V的VREF。
105636ycf0fc9shg5fhvgc.png
105636ragow3woowloh933.png
VREF设置为内部1.4V
105636ibpzb8xxzebk6kf3.png

软件部分

内部温度传感器的换算,根据前文找到的计算方法,编写代码如下:
float internal_temperature_sensor_calc(uint16_t adc_code) {
  /*参考MSPM0L系列Technical Reference Manual 2.2.5节*/
  float TSc = -1.75e-3; // MSPM0L1306 datasheet 7.13节
  float TStrim = 30;    // MSPM0L1306 datasheet 7.13节
  float Vref = 1.4;
  float Vsample = (Vref / 4096) * (adc_code - 0.5);
  float Vtrim = (Vref / 4096) * (TEMP_SENSE0 - 0.5);
  float Tsample = (1 / TSc) * (Vsample - Vtrim) + TStrim;
  return Tsample;
}

 

其中:
TEMP_SENSE0 = DL_FactoryRegion_getTemperatureVoltage();

完整的代码见文末。

发现问题

目前外部热敏电阻的读数正常。
105636p7cicri7icii6xkm.png
内部温度传感器的值有明显的问题。
室温24度左右,adc code是1896左右,而对应出厂校准的只读存储器里:30度校准值是377。
根据这一校准值得到的室温,与真实值相差甚远。

排除问题的一些尝试

1、更换ADC的参考电压,发现adc code随参考电压等比例变化,说明adc参考电压设置1.4V是正确的。
2、将手指放在芯片上加热芯片,可以看到adc code会减小,符合传感器的负温度系数特性,说明内部温度传感器应该是在工作的。
3、可能是校准值有误,需要重新校准。实际上TI在datasheet里提到了“通过用户校准可以实现更高的绝对精度”,因此手动校准是可行的。

手动校准

由于手头没有恒温箱,就用环境温度做一个简单的校准。
这里通过求解上述方程,得到30度校准值对应的adc码值“理论值”。使用python编写方程求解程序。
105636atpmuij5ulqmqv8w.png
得到TEMP_SENSE0的“理论值”为1867。
105636q72c8aq2a17s7ruq.png
修正后的代码,输出温度就基本正确了:
105636jkhe544hekhfje43.png
同时加热外置热敏电阻和MSPM0L1306,发现二者测量值都同步升高,截图是升到30度左右的结果。说明内置传感器是好的,只是需要手动校准。
105636c0r1247cs4l7i740.png

思考

仔细看了LaunchPad上的MSPM0L1306的丝印,没有找到工程样品(ES)的痕迹,应该是正式版,不知道为何温度的出厂校准相差甚远?

完整代码

SysConfig参考代码

/**
 * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
 * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
 * @cliArgs --device "MSPM0L130X" --package "VQFN-32(RHB)" --part "Default" --product "mspm0_sdk@1.20.00.06"
 * [url=home.php?mod=space&uid=304333]@versions[/url] {"tool":"1.18.0+3266"}
 */

/**
 * Import the modules used in this configuration.
 */
const ADC12  = scripting.addModule("/ti/driverlib/ADC12", {}, false);
const ADC121 = ADC12.addInstance();
const Board  = scripting.addModule("/ti/driverlib/Board");
const SYSCTL = scripting.addModule("/ti/driverlib/SYSCTL");
const VREF   = scripting.addModule("/ti/driverlib/VREF");

/**
 * Write custom configuration values to the imported modules.
 */
ADC121.$name                 = "ADC12_0";
ADC121.sampClkSrc            = "DL_ADC12_CLOCK_ULPCLK";
ADC121.sampClkDiv            = "DL_ADC12_CLOCK_DIVIDE_8";
ADC121.powerDownMode         = "DL_ADC12_POWER_DOWN_MODE_MANUAL";
ADC121.samplingOperationMode = "sequence";
ADC121.adcMem2chansel        = "DL_ADC12_INPUT_CHAN_7";
ADC121.adcMem3chansel        = "DL_ADC12_INPUT_CHAN_3";
ADC121.sampleTime0           = "40 us";
ADC121.adcMem0chansel        = "DL_ADC12_INPUT_CHAN_9";
ADC121.adcMem1chansel        = "DL_ADC12_INPUT_CHAN_11";
ADC121.endAdd                = 1;
ADC121.enabledInterrupts     = ["DL_ADC12_INTERRUPT_MEM0_RESULT_LOADED","DL_ADC12_INTERRUPT_MEM1_RESULT_LOADED"];
ADC121.adcMem1vref           = "VREF";
ADC121.peripheral.$assign    = "ADC0";
ADC121.adcPin9Config.$name   = "ti_driverlib_gpio_GPIOPinGeneric1";



VREF.checkVREFReady = true;

/**
 * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
 * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to
 * re-solve from scratch.
 */
ADC121.peripheral.adcPin9.$suggestSolution = "PA15";
Board.peripheral.$suggestSolution          = "DEBUGSS";
Board.peripheral.swclkPin.$suggestSolution = "PA20";
Board.peripheral.swdioPin.$suggestSolution = "PA19";
SYSCTL.peripheral.$suggestSolution         = "SYSCTL";
VREF.peripheral.$suggestSolution           = "VREF";

 

主程序代码

#include "ti_msp_dl_config.h"
#include <math.h>
#include <stdio.h>


volatile bool gCheckADC;

volatile uint32_t TEMP_SENSE0; // 内部温度传感器校准值
volatile uint16_t adc_thermistor;
volatile uint16_t adc_internal_temp_sensor;
volatile float t_thermistor;
volatile float t_internal_temp_sensor;

/*热电阻温度换算*/
float VBias = 3.30; // set the VBIAS voltage
// set the number of bits based on you ADC (2^# of ADC Bit Value)
unsigned int ADC_BITS = 4096;
float VTEMP = 0;     // set up the variable for the measured voltage
float THRM_TEMP = 0; // setup the variable for the calculated temperature

float thermistor_calc_temperature(uint16_t raw_ADC) {
  // THRM calculations via regression
  // Copied from TI Thermistor Design Tool Excel Doc
  float VTEMP = 0.0;
  float THRM_ADC = raw_ADC;

  float THRM_A0 = -4.232811E+02;
  float THRM_A1 = 4.728797E+02;
  float THRM_A2 = -1.988841E+02;
  float THRM_A3 = 4.869521E+01;
  float THRM_A4 = -1.158754E+00;

  VTEMP = (VBias / ADC_BITS) * THRM_ADC; // calculate volts per bit then
                                         // multiply that times the ADV value
  THRM_TEMP = (THRM_A4 * powf(VTEMP, 4)) + (THRM_A3 * powf(VTEMP, 3)) +
              (THRM_A2 * powf(VTEMP, 2)) + (THRM_A1 * VTEMP) +
              THRM_A0; // 4th order regression to get temperature
  return THRM_TEMP;
}

float internal_temperature_sensor_calc(uint16_t adc_code) {
  /*参考MSPM0L系列Technical Reference Manual 2.2.5节*/
  float TSc = -1.75e-3; // MSPM0L1306 datasheet 7.13节
  float TStrim = 30;    // MSPM0L1306 datasheet 7.13节
  float Vref = 1.4;
  float Vsample = (Vref / 4096) * (adc_code - 0.5);
  float Vtrim = (Vref / 4096) * (TEMP_SENSE0 - 0.5);
  float Tsample = (1 / TSc) * (Vsample - Vtrim) + TStrim;
  return Tsample;
}

int main(void) {
  /* Initialize peripherals and enable interrupts */
  SYSCFG_DL_init();
  NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);

  TEMP_SENSE0 = DL_FactoryRegion_getTemperatureVoltage();
  printf("TEMP_SENSE0=%d\n", TEMP_SENSE0);
  TEMP_SENSE0 = 1867; //使用自定义的校准值覆盖出厂校准值
  gCheckADC = false;
  while (1) {
    DL_ADC12_startConversion(ADC12_0_INST);

    /* Wait until all data channels have been loaded. */
    while (gCheckADC == false) {
      __WFE();
    }

    /* ch0:热电阻adc读数,
       ch1:内部温度传感器adc读数 */
    adc_thermistor = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0);
    adc_internal_temp_sensor =
        DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_1);
    gCheckADC = false;
    DL_ADC12_enableConversions(ADC12_0_INST);
    printf("adc_thermistor=%d, adc_internal_temp_sensor=%d\n", adc_thermistor,
           adc_internal_temp_sensor);
    t_thermistor = thermistor_calc_temperature(adc_thermistor);
    t_internal_temp_sensor =
         internal_temperature_sensor_calc(adc_internal_temp_sensor);
    printf("t_thermistor=%g, t_internal_temp_sensor=%g\n", t_thermistor, t_internal_temp_sensor);
    printf("\n");
  }
}

/* Check for the last result to be loaded then change boolean */
void ADC12_0_INST_IRQHandler(void) {
  switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) {
  case DL_ADC12_IIDX_MEM1_RESULT_LOADED:
    gCheckADC = true;
    break;
  default:
    break;
  }
}

 

Python用户校准程序代码

from sympy import *

# 已知环境温度为Tsample,ADC采样值为adc_code,求校准值TEMP_SENSE0
Tsample = 24.6
adc_code = 1895
TSc = -1.75e-3
TStrim = 30
Vref = 1.4

TEMP_SENSE0 = Symbol('TEMP_SENSE0')

Vsample = (Vref / 4096) * (adc_code - 0.5)
Vtrim = (Vref / 4096) * (TEMP_SENSE0 - 0.5)
eq = (1 / TSc) * (Vsample - Vtrim) + TStrim - Tsample
print(solve(eq, TEMP_SENSE0))

 

回复评论 (2)

基准没选对啊。要不就是转换不对吧。华氏和摄氏不会差两百℃啊
点赞  2023-11-7 12:40
引用: 吾妻思萌 发表于 2023-11-7 12:40 基准没选对啊。要不就是转换不对吧。华氏和摄氏不会差两百℃啊

基准有做实验对比哦。和单位没关系,就是校准值有问题,手动校准一下就好了

点赞  2023-11-7 12:46
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复