cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f0 ADC internal temperature sensor

German Tsvetkov
Associate II
Posted on November 10, 2017 at 07:40

Hello.

I need read temperature from internal sensor. But when i use code from examples, all time i have result more then 30 degrees of Celsius(~1760 - factory calibration value, ~1740 - ADC value in cold start with ~25 degrees in room).

How i can read the real temperature of MCU?

It's my init code. ADC start conversion by software and read result in interrupt.

#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t)0x1FFFF7B8)) // = 1767
#define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t)0x1FFFF7C2)) // = 1310
void init_periph_adc()
{
 // Enable clock on ADC
 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
 RCC->CR2 |= RCC_CR2_HSI14ON;
 while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0)
 ;
 // Start calibration of ADC
 ADC1->CR |= ADC_CR_ADDIS;
 while ((ADC1->CR & ADC_CR_ADEN) != 0)
 ;//TODO: make time management
 ADC1->CR |= ADC_CR_ADCAL;
 // Wait and of calibration
 while ((ADC1->CR & ADC_CR_ADCAL) != 0)
 ; //TODO: make time management
 // Select discontinious mode
 ADC1->CFGR1 |= ADC_CFGR1_DISCEN;
 // Select sampling mode
 ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
 //Enable temp sensor
 ADC->CCR |= ADC_CCR_TSEN;
 // Enable ADC interrupts
 ADC1->IER |= ADC_IER_EOCIE;
 // Set interrupt priority
 NVIC_SetPriority(ADC1_IRQn, 2);
 // Enable IRQ on NVIC
 NVIC_EnableIRQ(ADC1_IRQn);
 //Enable ADC
 ADC1->CR |= ADC_CR_ADEN;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

#adc-stm32f0 #internal-temperature-sensor
4 REPLIES 4
Posted on November 10, 2017 at 09:51

Show also the code performing the actual measurement.

JW

Posted on November 10, 2017 at 10:00

uint32_t adc_get_result()
{
 return adc_temp;
}

void ADC1_IRQHandler(void)
{
 if (ADC1->ISR & ADC_ISR_EOC)
 { // Conversion completed, data in the result register
 // Flag is cleared automatically after reading DR register
 adc_temp = (ADC1->DR);
 }
}
// main:
internal_temp = (int32_t)(adc_get_result());
internal_temp -= (int32_t) *TEMP30_CAL_ADDR;
internal_temp *= (int32_t)(110-30);
internal_temp /= (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
internal_temp += 30;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on November 10, 2017 at 13:03

Hi,

I can't see where you select the temperature channel for the ADC, I suppose it is not shown but actually there in your code. I havedone almost the same regarding the temperature reading with the difference that since my Vsup was 3.5V I had to also measure VrefInt in order to get the correct values. If recall correctly, my readings were also off by some °C (don't remember by how much), but in my application it was not critical as it was just an indication.

// Get temperature
int32_t temperature = (int32_t)ADC1->DR;
// Compute temperature with a resolution of 0.01°C
temperature = ((temperature * (int32_t)*VREFINT_CAL_ADDR) / VRef) - (int32_t)*TEMP30_CAL_ADDR;
temperature *= (int32_t)(11000 - 3000);
temperature = temperature / (int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature += 3000;�?�?�?�?�?�?�?�?

Yet I still try to get 0.01°C resolution 🙂

Posted on November 10, 2017 at 13:17

Yes, temperature channel is selected in different place, and calculated temperature value +-correct change if i heat MCU. 

My Vref is 3.3V, so i removed Vref coefficient.