cancel
Showing results for 
Search instead for 
Did you mean: 

Can't get internal temperature sensor via ADC

Joe Kissell
Associate II

I am having a tough time getting a valid temperature reading from my STM32L051K8U6 MCU. This should be an easy task. I've spent a LOT of time Googling and believe I have everything setup correctly. Most of the sample code online is identical, but it does not work for me.

Here is the code snippet I'm testing with:

#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 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);
  return(temperature);
}
 
 
void ConfigTemperature(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    ADC1->CFGR2 |= ADC_CFGR2_CKMODE;
 
    if ((ADC1->CR & ADC_CR_ADEN) != 0)
    {
     ADC1->CR &= (uint32_t)(~ADC_CR_ADEN);
    }
 
    ADC1->CR |= ADC_CR_ADCAL;
 
    while ((ADC1->ISR & ADC_ISR_EOCAL) == 0)
    {
        PRINTF("Calib");
    }
 
    ADC1->ISR |= ADC_ISR_EOCAL;
    ADC1->ISR |= ADC_ISR_ADRDY;
    ADC1->CR |= ADC_CR_ADEN;
 
    if ((ADC1->CFGR1 & ADC_CFGR1_AUTOFF) == 0)
    {
     while ((ADC1->ISR & ADC_ISR_ADRDY) == 0)
     {
         PRINTF("Enable");
     }
    }
 
    ADC1->ISR |= ADC_ISR_ADRDY;
    ADC1->CR |= ADC_CR_ADEN;
    ADC1->CFGR1 |= ADC_CFGR1_CONT;
    ADC1->CHSELR = ADC_CHSELR_CHSEL18;
    ADC1->SMPR |= ADC_SMPR_SMP;
    ADC->CCR |= ADC_CCR_TSEN;
 
    uint32_t measure = ADC1->DR;
    PRINTF("Measure %i\n\r", measure);
    PRINTF("The temperature value is %i\n\r",ComputeTemperature(measure));
}

The problem is that ADC1->DR always returns 62, which is way to low as it's calculated as -221 degrees C.

I'm sure I'm missing something simple, but can't seem to figure it out. Please help.

1 ACCEPTED SOLUTION

Accepted Solutions

To actually perform conversions, you need to start the ADC by setting ADCx_CR.ADSTART=1, and then wait for the conversion to end by checking ADCx_ISR.EOC.

Read chapter Continuous conversion mode (CONT=1) and Starting conversions (ADSTART) in RM.

There's also an error (but this does not actually influence your code) in line 25, you can't switch off ADEN by writing 0 to it, you have to write 1 to ADDIS. I know this error is in the Snippets and examples in appendix A of the RM; and I have already reported it here https://community.st.com/s/question/0D50X00009XkaB8SAJ/rm0367-stm32l0x3-discrepancies (unfortunately the answers got messed up when the forum migrated in 2018). This does not influence your code as ADEN is switched off after reset; this sequence would be needed only if you'd want to recalibrate the ADC some time after you've enabled it.

JW

View solution in original post

6 REPLIES 6
S.Ma
Principal

There should be sample code in cube for a nucleo or discovery of the corresponding STM32 family.

Otherwise, one issue here is

#define VDD_APPLI ((uint16_t) (330))

Replace this with a variable and use ADC Vref measurement to get it precisely.

Vref too has calibration point so beware of the reference manual initial first suggestion which is less accurate than the other one using the datasheet ADC electrical tables Vref calibration info.

S.Ma
Principal

Oh and make sure the ADC is calibrated.

To actually perform conversions, you need to start the ADC by setting ADCx_CR.ADSTART=1, and then wait for the conversion to end by checking ADCx_ISR.EOC.

Read chapter Continuous conversion mode (CONT=1) and Starting conversions (ADSTART) in RM.

There's also an error (but this does not actually influence your code) in line 25, you can't switch off ADEN by writing 0 to it, you have to write 1 to ADDIS. I know this error is in the Snippets and examples in appendix A of the RM; and I have already reported it here https://community.st.com/s/question/0D50X00009XkaB8SAJ/rm0367-stm32l0x3-discrepancies (unfortunately the answers got messed up when the forum migrated in 2018). This does not influence your code as ADEN is switched off after reset; this sequence would be needed only if you'd want to recalibrate the ADC some time after you've enabled it.

JW

Joe Kissell
Associate II

Thanks guys for the quick answers!

As waclawek.jan suggested, I added this code just before collecting the measurement.

ADC1->CR |= ADC_CR_ADSTART;
while((ADC1->ISR & ADC_ISR_EOC) == 0)   {;}

Now, I get an ADC value of 631 which translates into a temperature of 40C (104F). That's more in the ballpark, but I'm taking the measurement at room temperature. So, I was expecting something much closer to 71F.

I also measured VREF_INT as 1526 ==> 1.2995V

I don't need precision. I'd be happy to be within 3 degrees for my application. So, I think calibration would be an unnecessary step in this particular case.

Any idea why my measurement would be off by so many degrees?

I

The sensor measures the internal temperature of the chip, not the ambient.

JW

Joe Kissell
Associate II

Right, but I expected something much closer to ambient.

I got it figured out now. Had some other experimental ADC code in place that was affecting my results. I took it out and now i'm getting 32C (86F) which is much more reasonable. Put the code in a loop and took a heat gun to the MCU and was able to watch the temperature rise and then fall as I removed the heat.

Thanks again!