0
\$\begingroup\$

I've been trying to measure the MCU's (STM32F103RB) temperature as part of a FreeRTOS application. I've tried initializing the ADC both with the low and the high-level HAL functions, but whenever I try to get data, the variable storing them has a value of about 68 (when normally it should be ~1500 - 1600 in room temperature). Any ideas?

Code follows here: TempMsr.c - HAL

#include "Peripherals/TempMsr.h"

volatile int32_t sensorData = 0;
volatile int32_t temp = 0;
ADC_HandleTypeDef adc1_config;
ADC_ChannelConfTypeDef adc1_channel;

int32_t getTemp()
{
    sensorData = HAL_ADC_GetValue(&adc1_config);
    temp = (int32_t)( ( (10 * V25 - 8 * sensorData) / (AVGSLOPE * 10) ) + 25 + BIAS);
    //manufacturer's formula for determining the temperature in Celsius, adjusted for unit
    //compliance and for minimizing errors due to possible floating-point operations
    return sensorData;
}

void ADC_TempMsr_Init()
{
    ADC_Config();
    HAL_ADC_Init(&adc1_config);
    HAL_ADC_ConfigChannel(&adc1_config, &adc1_channel);
}

void ADC_Config()
{
    adc1_config.Instance = ADC1;
    adc1_config.Init.ScanConvMode = ADC_SCAN_DISABLE;
    adc1_config.Init.ContinuousConvMode = ENABLE;
    adc1_config.Init.DiscontinuousConvMode = DISABLE;
    adc1_config.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    adc1_config.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    adc1_config.Init.NbrOfConversion = 1;

    adc1_channel.Channel = ADC_CHANNEL_TEMPSENSOR;
    adc1_channel.Rank = ADC_REGULAR_RANK_1;
    adc1_channel.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;  //~17 us, manufacturer-suggested time for temp sampling
}

TempMsr.c - Low-level:

void ADC_TempMsr_Init()
{
    ADC_Config();

    LL_ADC_Enable(ADC1);

    LL_ADC_StartCalibration(ADC1);
}

void ADC_Config()
{
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);  //enable the clock for ADC1

    LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_TEMPSENSOR);
    uint32_t wait_loop_index = 80;  //CPU cycles which correspond to ~10 us, suggested stabilization time for temp.sensor stabilization

    while(wait_loop_index != 0)
    {
        wait_loop_index--;
    }

    /* Set ADC group regular trigger source */
    LL_ADC_REG_SetTriggerSource(ADC1, LL_ADC_REG_TRIG_SOFTWARE);

    /* Set ADC group regular continuous mode */
    LL_ADC_REG_SetContinuousMode(ADC1, LL_ADC_REG_CONV_SINGLE);

    /* Set ADC group regular sequencer length and scan direction */
    LL_ADC_REG_SetSequencerLength(ADC1, LL_ADC_REG_SEQ_SCAN_DISABLE);

    /* Set ADC group regular sequence: channel on the selected sequence rank. */
    LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_TEMPSENSOR);

    LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_16, LL_ADC_SAMPLINGTIME_239CYCLES_5);
}

The corresponding header file (TempMsr.h):

#ifndef INC_TEMPMSR_H_
#define INC_TEMPMSR_H_

#include "stm32f1xx_hal.h"
//#include "stm32f1xx_ll_adc.h"
//#include "stm32f1xx_ll_bus.h"

#define AVGSLOPE 4.3
//average slope of T-V chart according to datasheet pg 79
//(min is 4 mV/C, max 4.6, default (4.3): typical)

#define V25 1430
//voltage of temperature sensor at 25C according to datasheet pg 79 (in mV)
//(min is 1340, max is 1520, default(1430): typical)

#define BIAS 20
//according to the manual (pg 235), due to mfg processes
//there is an offset in the V(T) plot different
//to every chip (up to +-45oC) that needs to be found.
//(default is 0 so it MUST be calculated before any meaningful measurements
//are made)

int32_t getTemp();  //returns current MCU temp. in Celsius
void ADC_TempMsr_Init();  //initializes the ADC, this needs to be run in prvHardwareSetup()
void ADC_Config();

Finally, the FreeRTOS task:

void vTempTask(void *pvParameters)
{
    while(1)
    {
        xSensorData.temp = getTemp();  //continually update the appropriate variable inside the sensor data struct
        vTaskDelay(pdMS_TO_TICKS(1000));   //1 second per measurement is enough
    }
}

Thanks in advance.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ You are setting the sampling time wrong. You have to use a predefined value not a multiple of ADC_SAMPLETIME_1CYCLE_5. There are only a few bits to set the sampling time and 91*ADC_SAMPLETIME_1CYCLE_5 probably results in the sampling time still being just 1.5 cycles, which is too fast. \$\endgroup\$
    – Arsenal
    Oct 30 '18 at 16:13
  • \$\begingroup\$ Fixed that, unfortunately it didn't change anything :( It's still stuck at 68. \$\endgroup\$ Oct 30 '18 at 16:26
1
\$\begingroup\$

I'm not 100% sure about HAL but I think you only read the value from the registers - it doesn't start the conversion. Software trigger means that you need to manually start the conversion. Look for a function which does that in HAL.

\$\endgroup\$
5
  • \$\begingroup\$ It worked! Many thanks. Lesson learned: always remember to activate the conversion when grabbing values from an ADC. \$\endgroup\$ Oct 30 '18 at 16:44
  • \$\begingroup\$ @lightspot21 glad to help \$\endgroup\$ Oct 30 '18 at 16:46
  • \$\begingroup\$ @lightspot21 also don't be surprised if the value is strange. From my experience they never really match environment temperature. \$\endgroup\$ Oct 30 '18 at 17:05
  • \$\begingroup\$ Actually I think I read somewhere in the manual that these have a max bias of 45 degreees over or under the correct temperature. I think it's good enough for measuring core temperature though. \$\endgroup\$ Oct 30 '18 at 17:11
  • \$\begingroup\$ @lightspot21 there are calibration values stored which makes it accurate to about +- 6 K, see here: electronics.stackexchange.com/questions/324321/… \$\endgroup\$
    – Arsenal
    Oct 30 '18 at 20:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.