cancel
Showing results for 
Search instead for 
Did you mean: 

[STM32G474] - ADC Error

JTánt.1
Associate II

Hello everyone,

I am currently working with the STM32G474QET6.

Trying to measure Honeywell pressure sensors whose output voltage ranges from 0V to 3V.

The problem is that the measurements have a much greater error than indicated in the data sheet.

To rule out that the error is caused by the sensor, I mounted a constant voltage of 1.65V on the channels of the ADC with a controlled source and a pull-down resistor and I find that the error is still there.

Numerically I have a measurement error of ≈50mV (≈60 counts).

The strange thing is that without making any type of correction, the full scale values, Vin = Vref (3.3V), read them correctly but the error is in the lower voltages. And if I apply the correction by modifying the value of "hadc1.Init.GainCompensation" the intermediate values (1.65V) I read them well but the error is transferred to the values close to Vref.

Has anyone come across this problem or can you think of the origin of it?

I leave some information to be able to guide better,

/* ADC1 init function */
void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 9;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = ADC_REGULAR_RANK_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_7;
  sConfig.Rank = ADC_REGULAR_RANK_6;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = ADC_REGULAR_RANK_7;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = ADC_REGULAR_RANK_8;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_12;
  sConfig.Rank = ADC_REGULAR_RANK_9;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}
void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  /* DMA1_Channel2_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
  /* DMA1_Channel3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
 
}

Thank you all.

Kind regards,

Juan Tántera.

2 REPLIES 2
Igor Cesko
ST Employee

The problem seems to be not in firmware but in the hardware. Please check the decoupling capacitors between VREF+ and VSSA. There is very important to correctly design the decoupling capacitors on VREF+ : there must be ceramic capacitors 1uF + 100nF place immediately between VREF+ and VSSA pins (each millimeter is important). Please read application note AN5346 where is explanation why is this important (Chapter "2.5 Application design to reach ADC maximum conversion speed"). If this VREF+ decoupling is not perfect then is necessary to decrease ADC clock frequency: As first investigation step - to detect if the problem is in this decoupling - you can decrease the ADC clock frequency 10 times and check if behavior changed.

Additional note: according the firmware I see that you are using very short sampling time (2.5 ADC clock cycles only). Usually the signal from pressure sensor is not so strong and impedance of the sensor output is higher. Please increase the sampling time according to impedance of the pressure sensor: to be able to charge the sampling capacitor (inside ADC: ~5pF) during the sampling time (read the AN2834 to help to design the correct sampling time according source impedance).

Give me please feedback if proposed solution helped.

Regards

Igor

Hi @Igor Cesko​ and thank you for your help.

After trying differents scenarios with STMCubeMx configuration. I found the solution calling "HAL_ADCEx_Calibration_Start()" method.

Which leads me to wonder why isn't this method implemented in the Init routine?

Thank you so much for your support.

Regards,

Juan.