cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103RC Wrong ADC Readings on Vrefint and TempSensor Channels

Chao
Senior

Hi,

The ADC test has only 2 channels: Vrefint and TempSensor. The following ADC result (convertedData) is read out through DMA:

tick = 1s - convertedData[0] = 113968573   convertedData[1] = 0
tick = 2s - convertedData[0] = 113837503   convertedData[1] = 0  
tick = 3s - convertedData[0] = 96339657    convertedData[1] = 0   
tick = 4s - convertedData[0] = 113837502   convertedData[1] = 0   
tick = 5s - convertedData[0] = 113837503   convertedData[1] = 0   
tick = 6s - convertedData[0] = 96405193    convertedData[1] = 0   
tick = 7s - convertedData[0] = 113837503   convertedData[1] = 0   
tick = 8s - convertedData[0] = 113837502   convertedData[1] = 0   
tick = 9s - convertedData[0] = 96405192    convertedData[1] = 0   

 Where convertedData[0] is the ADC reading of Vrefint which should be 4095, the other is that of TempSensor which should not be 0.

The ADC configuration:

Chao_0-1710602367613.png

Chao_1-1710602395741.png

Chao_2-1710602434590.png

The code:

  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1);
  HAL_ADC_Start_DMA(&hadc1, convertedData, 2);
  HAL_Delay(1);
  startTick = HAL_GetTick();
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if (dmaTransferStatus == DMA_COMPLETED)
	  {
		  Vrefint = convertedData[0] * 3300 / 4095; /* VREF = VDDA = 3300mV */
		  Vsense = convertedData[1] * 3300 / 4095;
		  Tmcu = ((1430 - Vsense) / 4.3) + 25;		/* Temperature (in °C) = {(V_25 - V_SENSE ) / Avg_Slope} + 25 */
		  dmaTransferStatus = DMA_NOT_STARTED;
	  }
	  if ((HAL_GetTick() - startTick) > 1000)
	  {
		  tick++;
		  startTick = HAL_GetTick();
		  printf("tick = %ds - convertedData[0] = %d   convertedData[1] = %d\n",
		          tick, convertedData[0], convertedData[1]);
		  convertedData[0] = 0;
		  convertedData[1] = 0;
		  HAL_ADC_Start_DMA(&hadc1, convertedData, 2);
		  dmaTransferStatus = DMA_NOT_COMPLETED;
	  }
  }
  /* USER CODE END 3 */
}
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	dmaTransferStatus = DMA_COMPLETED;
}
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart5, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
/* USER CODE END 4 */
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 2;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_VREFINT;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
static void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

 

Any suggestions and comments would be appreciated

Regards

Chao

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

You have likely defined convertedData as a uint32_t array instead of a uint16_t array.

 

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

8 REPLIES 8
TDK
Guru

You have likely defined convertedData as a uint32_t array instead of a uint16_t array.

 

If you feel a post has answered your question, please click "Accept as Solution".

Thanks. You are right. 

After having changed to uint16_t, the readings are still wrong:

 

tick = 1s - convertedData[0] = 1470   convertedData[1] = 1742   Vrefint = 1184   Tmcu = 31
tick = 2s - convertedData[0] = 1470   convertedData[1] = 1741   Vrefint = 1184   Tmcu = 31
tick = 3s - convertedData[0] = 1470   convertedData[1] = 1740   Vrefint = 1184   Tmcu = 31
tick = 4s - convertedData[0] = 1740   convertedData[1] = 1470   Vrefint = 1184   Tmcu = 31
tick = 5s - convertedData[0] = 1470   convertedData[1] = 1740   Vrefint = 1184   Tmcu = 31
tick = 6s - convertedData[0] = 1471   convertedData[1] = 1741   Vrefint = 1185   Tmcu = 31
tick = 7s - convertedData[0] = 1740   convertedData[1] = 1470   Vrefint = 1185   Tmcu = 31
tick = 8s - convertedData[0] = 1471   convertedData[1] = 1740   Vrefint = 1185   Tmcu = 31
tick = 9s - convertedData[0] = 1470   convertedData[1] = 1740   Vrefint = 1184   Tmcu = 31
tick = 10s - convertedData[0] = 1740   convertedData[1] = 1470   Vrefint = 1184   Tmcu = 31

 

And the data pattern looks like the readings of the two channels are mixed up.

Not like with G070, F103 does not have configuration options on sequence conversion.

What I expect for the ADC behaviour is:

1. it completes a conversion every second

2. for each conversion, it converts the both channel one after another

3. the DMA transfers the conversion result into convertedData once a second

I am not sure whether or not it does what I expect.

The room temperature is around 21 degree centigrade while the reading is 31.

The temperature sensor characteristics:

Chao_0-1710610664326.png

 

You have continuous conversions on, so the ADC is constantly running. For what you are doing, this seems like the right thing to do. Just set it to convert those 2 channels forever, and put them in a circular buffer. Read them out whichever you want. Only call HAL_ADC_Start_DMA once at the start.

> The room temperature is around 21 degree centigrade while the reading is 31.

This is consistent. The reading you are getting is the junction temperature on the chip, which will be higher than ambient as the chip is using power and heating up. A delta of 10 C is normal. Slowing down your chip so it uses less power and heats up more will reduce the difference. If you want to measure ambient temp, you will need an external sensor that stays at ambient temperature.

If you feel a post has answered your question, please click "Accept as Solution".

I will try the circular buffer later.

But if we put the temperature value aside, the converted Vrefint is definitely wrong, it should be very close to 3300mV rather than 1184mV.

I tested on a Nucleo-G070RB board, the Vrefint is quite stable at 3300mV, and the Tmcu is about 23 -25 C while the room temperature is at 20 C. The both tests are at the same place.

There must be something wrong somewhere in the code or the configuration.

Your on F103 - ds:

AScha3_0-1710708461400.png

So 1184mV is in spec.

If you feel a post has answered your question, please click "Accept as Solution".

> But if we put the temperature value aside, the converted Vrefint is definitely wrong, it should be very close to 3300mV rather than 1184mV.

Why do you think that? What does the data sheet or reference manual say? It should generally be ~1.2 V which is what you're seeing.

If you feel a post has answered your question, please click "Accept as Solution".

Thank you for reminding me of that.

I checked it in the datasheet, I think I mixed up the concepts and usages of VREF and Vrefint, I thought they are the same because VREF is internally connected to VDDA, and Vrefint is the internal reference voltage. So what's the difference? How one should use Vrefint ?

VREFINT is an internal ~ 1.2 V voltage. VREF+ is the reference voltage on the ADC converter (and other things). They are not related.

 

The uses for VREFINT are as follows:

  • To provide general health of the chip. If it no longer reports 1.2 V, perhaps the hardware is damaged.
  • Assuming it is outputting 1.2V, you can estimate what VREF+ is based on the value you get back, since ADC counts = 4096 * voltage / VREF+. If you know voltage and counts, you can estimate VREF+.
If you feel a post has answered your question, please click "Accept as Solution".