STM32 ADC Temperature Measurement – ADC Based Temperature Measurement on FreeRTOS

adcfreertosstm32

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.

Best Answer

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.