2020-01-20 12:24 AM
I'm having trouble reading the temperature, its values are incorrect. The temperature in the room is 22C and the temperature of the sensor shows 55C (selfheating and the measurement error cannot be that big). I have many times checked the correctness of the code, and I use the functions recommended by the manufacturer (Code examples from reference manual). I have no idea why it doesn't work.
Data:
STM32L0x1 family MCU
3.3V supply voltage
Clock frequency: 2.097MHz (MSI)
Problems I ruled out:
1) ADC sampling time too short (it should be longer than 10us and it is).
2) I tested the code on different MCUs of the same model, and also on other models of STM32L0x1 family.
3) VDD of the chip is 3.3V, not e.g. 3.0V, there is no mistake here.
4) The temperature is certainly not about 55C because I checked it with two independent methods (thermal camera and thermocouple) and certainly the housing temperature does not exceed 22C.
5) The board on which I test this circuit is well proven in other ADC applications and behaves flawlessly.
Below I paste the program code:
#include "stm32l0xx.h"
#define TEMP130_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007E))
#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007A))
#define VDD_CALIB ((uint16_t) (300))
#define VDD_APPLI ((uint16_t) (330))
int32_t temperature_in_C;
uint16_t temperature_ADC_value;
int32_t temp130_cal_value;
int32_t temp30_cal_value;
int32_t ComputeTemperature(uint32_t measure)
{
int32_t temperature;
temperature = ((measure * VDD_APPLI / VDD_CALIB) - (int32_t) *TEMP30_CAL_ADDR );
temperature = temperature * (int32_t)(130 - 30);
temperature = temperature / (int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature = temperature + 30;
return(temperature);
}
void ADC_Init()
{
RCC->APB2ENR |= RCC_APB2ENR_ADCEN; /* Enable ADC clock */
ADC1->CFGR2 |= ADC_CFGR2_CKMODE_0
| ADC_CFGR2_CKMODE_1; /* ADC Clock = PCLK (2.097MHz) */
ADC->CCR |= ADC_CCR_LFMEN; /* Enable if ADC Clock Freq < 3.5MHz */
ADC1->CFGR1 |= ADC_CFGR1_CONT; /* Continous conversions */
ADC1->CHSELR = ADC_CHSELR_CHSEL18; /* Channel 18 - Temperature sensor */
ADC1->SMPR |= ADC_SMPR_SMP; /* Sampling time - 160.5 ADC cycles */
ADC->CCR |= ADC_CCR_TSEN; /* Enable temperature sensor */
ADC1->ISR |= ADC_ISR_ADRDY; /* Clearing bit ADRDY (ADC ready) */
ADC1->CR |= ADC_CR_ADEN; /* Enable ADC */
while((ADC1->ISR & ADC_ISR_ADRDY) == 0) /* Wait for turn on */
;
ADC1->CR |= ADC_CR_ADSTART; /* Start */
}
int main(void)
{
ADC_Init();
while (1)
{
for(int i = 0; i < 10000; i++) /* Delay */
;
temperature_ADC_value = ADC1->DR; /* Debug */
temp130_cal_value = (int32_t)(*TEMP130_CAL_ADDR); /* Debug */
temp30_cal_value = (int32_t)(*TEMP30_CAL_ADDR); /* Debug */
temperature_in_C = ComputeTemperature(temperature_ADC_value);
}
return 0;
}
Example from debugging in STM Studio:
Solved! Go to Solution.
2020-01-20 12:48 AM
You are supposed to run ADC calibration (see Calibration (ADCAL) subchapter in ADC chapter) before using the ADC.
How does VREFINT_CAL compare to measured value of VREFINT on the same chip?
JW
2020-01-20 12:48 AM
You are supposed to run ADC calibration (see Calibration (ADCAL) subchapter in ADC chapter) before using the ADC.
How does VREFINT_CAL compare to measured value of VREFINT on the same chip?
JW
2020-01-20 01:05 AM
As far as I understand, the manufacturer checked the ADC reading at VREF = 3V (VDD_CALIB) at 30C and 130C and stored it in FLASH memory. This allows me to calibrate the temperature sensor. If I use VREF = 3.3V (VDD_APPLI) the ADC reading should be smaller at the same temperature (for 3.0V and 30C the manufacturer wrote the value 657, so for 3.3V I should have for this temperature proportionally about 597).
Besides, the code that calculates the temperature is taken from Reference Manual from "Code examples" section, so I don't expect that there would be such a big error.
2020-01-20 01:07 AM
No, sorry, my original post was a mistake (I've just worked with an externally connected thermistor and confused things, my bad), I corrected it.
JW
2020-01-20 01:14 AM
Thank you very much. I didn't expected it to be enough to just calibrate the ADC. Now the result is as expected (T = 30C).