cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 internal temperature sensor always returns 0x0FFF

Corono
Associate III

Hi

I'm using the STM32F091RC controller and I try to read the value from the internal temperature sensor using the HAL functions in a FreeRTOS project. The code I use:

static HAL_StatusTypeDef initADC(void) {
 
  /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
   */
  hadc.Instance = ADC1;
  hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  hadc.Init.ContinuousConvMode = ENABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 
  if (HAL_ADC_Init(&hadc) != HAL_OK) {
    printLogError(ERR_HalAdcError, "Initialization of ADC failed, error code %u", hadc.ErrorCode);
    errorHandler();
  }
 
  if (HAL_ADCEx_Calibration_Start(&hadc) != HAL_OK) {
    printLogError(ERR_HalAdcError, "Calibration of ADC failed, error code %u", hadc.ErrorCode);
    errorHandler();
  }
 
  return HAL_OK;
}

This function is called when the peripheral "internal temperature sensor" is enabled.

After enabling it, I try to read the value of the temperature sensor with the following code:

  uint32_t adc_value;
 
  ADC_ChannelConfTypeDef adc_config = { 0 };
  //Add channel to Conversion list
  adc_config.Channel = ADC_CHANNEL_TEMPSENSOR;
  adc_config.Rank = ADC_RANK_CHANNEL_NUMBER;
  adc_config.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
 
  HAL_StatusTypeDef status;
  status = HAL_ADC_ConfigChannel(&hadc, &adc_config);
  if (status != HAL_OK) {
    printLogWarning(ERR_HalAdcError,
                    "ADC configuration of channel %u failed, error code %u",
                    hardware_settings->analogInputNr,
                    hadc.ErrorCode);
    return halToCANxError(status);
  }
 
  // stop scheduling as a workaround mentioned in
  // the errata sheet "ES0282 Rev 3" in May 2018
 vTaskSuspendAll();
 
  status = HAL_ADC_Start(&hadc);
  if (status != HAL_OK) {
    printLogWarning(ERR_HalAdcError,
                    "Starting of ADC conversion failed, error code %u",
                    hadc.ErrorCode);
    return halToCANxError(status);
  }
 
  status = HAL_ADC_PollForConversion(&hadc, 10);
  if (status != HAL_OK) {
    printLogWarning(ERR_HalAdcError,
                    "Waiting for ADC conversion failed, error code %u",
                    hadc.ErrorCode);
    return halToCANxError(status);
  }
 
  adc_value = HAL_ADC_GetValue(&hadc);
 
  status = HAL_ADC_Stop(&hadc);
  if (status != HAL_OK) {
    printLogWarning(ERR_HalAdcError,
                    "Stopping ADC conversion failed, error code %u",
                    hadc.ErrorCode);
    return halToCANxError(status);
  }
  xTaskResumeAll();
  // restart scheduling
 
  //Remove channel to Conversion list
  adc_config.Rank = ADC_RANK_NONE;
 
  status = HAL_ADC_ConfigChannel(&hadc, &adc_config);
  if (status != HAL_OK) {
    printLogWarning(ERR_HalAdcError,
                    "Removing channel %u from ADC conversion list failed, error code %u",
                    hardware_settings->analogInputNr,
                    hadc.ErrorCode);
    return halToCANxError(status);
  }
...

The same code is used for hardware ADC inputs and there it works. But for the temperature sensor, the feedback value is always 0x0FFF.

Any idea what the problem could be?

Thanks.

Corono

7 REPLIES 7

I thought the internal temperature readings need a lot of sample clock cycles. Are you sure 28 is enough? The 32G070 we are working on want's around 90 sample clock cycles to take the internal temp.

ADC_SAMPLETIME_28CYCLES_5 ?

Corono
Associate III

Thanks for the answer.

I also tried with ADC_SAMPLETIME_239CYCLES_5 which is the maximum that is available as #define. The result is the same, 0x0FFF.

Well that's definitely more than enough time and you still reading the max twelve bit value. If you are sure that the End of Sample flag is set, meaning that the HAL_ADC_PollForConversion() returned a real sample and not a timeout, then my guess would be some clock setup given you have enabled the internal temp sensor. We don't run the HAL stuff(just Low Level) so I've got nothing for you other than look at a HAL example and go line by line. The only other guess is the continuous conversion setting as we run four ADC channels in a LL_ADC_REG_CONV_SINGLE(single) mode with a sequencer length of four.

  LL_ADC_ClearFlag_CCRDY(ADC1);
  ADC_REG_InitStruct.TriggerSource		= LL_ADC_REG_TRIG_SOFTWARE;
  ADC_REG_InitStruct.SequencerLength 	= LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS;
  ADC_REG_InitStruct.SequencerDiscont 	= LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode 	= LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.DMATransfer 		= LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
  ADC_REG_InitStruct.Overrun 			= LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);

Corono
Associate III

I checked with the debugger. It says that the End of Conversion flag (EOC) and the End of Sampling flag (EOSMP) are both set before reading the ADC value. So yes, it seems that the conversion is done.

Also the temperature sensor enable flag TSEN is set correctly. So the problem seems to be somewhere else...

  • In the debugger is the EOC flag set before you call HAL_ADC_Start()?
  • No DMA setups where the data could be move into memory?
  • Any chance that you could try this experiment before the RTOS starts up? Maybe move the code into main just before you launch the RTOS tasks?

If neither of these gives you any clues then it has got to be something basic in the ADC setup.

Corono
Associate III

Thanks for the aswer.

I will try to play with DMA and FreeRTOS and I will also try a continuous conversion.

I can answer the first point;

Entering the ADC reading function

  • EOC = 0
  • EOSMP = 0
  • TSEN = 0
  • CHSEL16 = 0

Config Channel (Temperature sensor)

  • TSEN => 1
  • CHSEL16 => 1

ADC Start

(The debug step probably takes longer than the conversion)

  • EOC => 1
  • EOSMP => 1

ADC Stop

  • EOSMP => 0
  • EOC => 0 (one debug step later)

Config Channel (RANK_NONE)

  • TSEN => 0
  • CHESEL16 => 0

Edit:

Made a test: I enable continuous conversion once and then I read the value from time to time. Works perfectly for e.g. hardware assigned channel0, but not for the temperature sensor, the result is always 0x0FFF.

The interessting thing: I tried to sample the internal reference voltage ADC_CHANNEL_VREFINT. Same behaviour, always 0x0FFF. It seems that something is wrong with the ADC settings or this "internal channels". Any idea?

I've been looking at ST's RM0454(Reference Manual) pg 308 which has a lot of detailed info on taking a ADC reading on the internal micro temperature. I'm not sure how different your STM32F0 is from the STM32G0 but the doc basically is talking about how the temperature reading uses the processor's internal reference voltage. I would have thought ST would have had some good examples of using HAL to take the micro temp but we have not had any luck getting our new G0 ADC's working with the new Low Level drivers from Cube.