Skip to main content
Associate
September 16, 2024
Question

STM32G431KB ADC Wrong value

  • September 16, 2024
  • 4 replies
  • 2525 views

Hi everyone,

I am using the ADC2 of the STM32G431KB to read a voltage value. I am actualy measuring 0.8V on the pin of the ADC with a multimeter, but while debuging, the conversion give me back 0.12V (~150 from the ADC, instead of ~1000). 

This is my config and the way I do the conversion. 

void MX_ADC2_Init(void)
{

 /* USER CODE BEGIN ADC2_Init 0 */

 /* USER CODE END ADC2_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC2_Init 1 */

 /* USER CODE END ADC2_Init 1 */

 /** Common config
 */
 hadc2.Instance = ADC2;
 hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4;
 hadc2.Init.Resolution = ADC_RESOLUTION_12B;
 hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc2.Init.GainCompensation = 0;
 hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
 hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV; 
 hadc2.Init.LowPowerAutoWait = DISABLE;
 hadc2.Init.ContinuousConvMode = ENABLE; 
 hadc2.Init.NbrOfConversion = 2;
 hadc2.Init.DiscontinuousConvMode = DISABLE;
 hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc2.Init.DMAContinuousRequests = ENABLE;
 hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc2.Init.OversamplingMode = DISABLE;
 if (HAL_ADC_Init(&hadc2) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VOPAMP2;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;
 sConfig.Rank = ADC_REGULAR_RANK_2;
 sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 if(HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED) != HAL_OK){
 Error_Handler();
 }


 /* USER CODE BEGIN ADC2_Init 2 */
 HAL_ADC_Start_DMA(&hadc2, (uint32_t *) &analog_input.unmap[2], 2);
 /* USER CODE END ADC2_Init 2 */

}

float ll_motor_GetVoltage(void) {
 return (((float)analog_input.voltage * VREF_ADC) / (ADC_RESOLUTION));
}

The input_voltage is linked to the first chanel (VOPAMP 2) of the ADC and put in analog_input.unmap[2] by the dma. 
VREF_ADC = 3.3f
ADC_RESOLUTION = 4096 (12bits)


Do you have an idea on the wrong value origin ? 

Best regards,

Clément.

4 replies

Technical Moderator
September 16, 2024

Hello @cppoisson and welcome to the ST Community :)

On a first step, I advise you to take a look at this errata sheet related to the STM32G431xx devices, in the ADC section and check if you have the same conditions as described in the document.

Make sure that the ADC is properly calibrated. For that, please follow the calibration procedure as described in the RM0440.

ImenD_0-1726482942287.png

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Thanks
MasterT
Lead II
September 16, 2024
 sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

you say VOPAMP 2 , but config is different. Also post opa setup

cppoissonAuthor
Associate
September 19, 2024

Yes there it is :

void MX_OPAMP2_Init(void)
{

 /* USER CODE BEGIN OPAMP2_Init 0 */

 /* USER CODE END OPAMP2_Init 0 */

 /* USER CODE BEGIN OPAMP2_Init 1 */

 /* USER CODE END OPAMP2_Init 1 */
 hopamp2.Instance = OPAMP2;
 hopamp2.Init.PowerMode = OPAMP_POWERMODE_NORMAL;
 hopamp2.Init.Mode = OPAMP_FOLLOWER_MODE;
 hopamp2.Init.NonInvertingInput = OPAMP_NONINVERTINGINPUT_IO0;
 hopamp2.Init.InternalOutput = ENABLE;
 hopamp2.Init.TimerControlledMuxmode = OPAMP_TIMERCONTROLLEDMUXMODE_DISABLE;
 hopamp2.Init.UserTrimming = OPAMP_TRIMMING_FACTORY;
 if (HAL_OPAMP_Init(&hopamp2) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN OPAMP2_Init 2 */

 /* USER CODE END OPAMP2_Init 2 */

}
/* OPAMP3 init function */
void MX_OPAMP3_Init(void)
{

 /* USER CODE BEGIN OPAMP3_Init 0 */

 /* USER CODE END OPAMP3_Init 0 */

 /* USER CODE BEGIN OPAMP3_Init 1 */

 /* USER CODE END OPAMP3_Init 1 */
 hopamp3.Instance = OPAMP3;
 hopamp3.Init.PowerMode = OPAMP_POWERMODE_NORMAL;
 hopamp3.Init.Mode = OPAMP_FOLLOWER_MODE;
 hopamp3.Init.NonInvertingInput = OPAMP_NONINVERTINGINPUT_IO0;
 hopamp3.Init.InternalOutput = ENABLE;
 hopamp3.Init.TimerControlledMuxmode = OPAMP_TIMERCONTROLLEDMUXMODE_DISABLE;
 hopamp3.Init.UserTrimming = OPAMP_TRIMMING_FACTORY;
 if (HAL_OPAMP_Init(&hopamp3) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN OPAMP3_Init 2 */

 /* USER CODE END OPAMP3_Init 2 */

}


The opamp 2 is used to realise a voltage measurement and the opamp 3 is also used for another measurement, but for now i am focusing on the voltage measurement with the opamp 2.

Thank you for the reply !

MasterT
Lead II
September 19, 2024

than line of code should be changed:

sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

to

sConfig.Channel = ADC_CHANNEL_VOPAMP2;

cppoissonAuthor
Associate
September 20, 2024

I am trying to measure a voltage on the ADC2 of the STM32G431KB from the opamp in following mode through the DMA (this is the config : PA7 -> VOPAMP2 + -> ADC2 channel VOPAMP2 -> DMA2 Chanel 2).  

My main problem is that the ADC is not giving back the right voltage value (which is 0.8V measured with a multimeter) when I am using the ContinuousConvMode in ENABLE. When it is DISABLE, I read the right value but only one time and then the ADC value (or the DMA value) is not updated.

There is my ADC2 and DMA2 Config :

 

 

hadc2.Instance = ADC2;
 hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV256;
 hadc2.Init.Resolution = ADC_RESOLUTION_12B;
 hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc2.Init.GainCompensation = 0;
 hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; // ENABLE
 hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV; 
 hadc2.Init.LowPowerAutoWait = DISABLE;
 hadc2.Init.ContinuousConvMode = ENABLE; 
 hadc2.Init.NbrOfConversion = 1; // 2
 hadc2.Init.DiscontinuousConvMode = DISABLE;
 hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc2.Init.DMAContinuousRequests = ENABLE; // ENABLE
 hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc2.Init.OversamplingMode = DISABLE;
 if (HAL_ADC_Init(&hadc2) != HAL_OK)
 {
 Error_Handler();
 }

 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VOPAMP2;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 if(HAL_ADCEx_Calibration_Start(&hadc2, ADC_SINGLE_ENDED) != HAL_OK){
 Error_Handler();
 }


 /* USER CODE BEGIN ADC2_Init 2 */
 HAL_ADC_Start_DMA(&hadc2, (uint32_t *) &analog_input.unmap[2], 1);
}


/** Initializes the peripherals clocks
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
 PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }

 /* ADC2 clock enable */
 HAL_RCC_ADC12_CLK_ENABLED++;
 if(HAL_RCC_ADC12_CLK_ENABLED==1){
 __HAL_RCC_ADC12_CLK_ENABLE();
 }

 /* ADC2 DMA Init */
 /* ADC2 Init */
 hdma_adc2.Instance = DMA2_Channel2;
 hdma_adc2.Init.Request = DMA_REQUEST_ADC2;
 hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
 hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
 hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
 hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
 hdma_adc2.Init.Mode = DMA_CIRCULAR;
 hdma_adc2.Init.Priority = DMA_PRIORITY_HIGH;
 if (HAL_DMA_Init(&hdma_adc2) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc2);

 /* ADC2 interrupt Init */
 HAL_NVIC_SetPriority(ADC1_2_IRQn, 7, 0);
 HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
 /* USER CODE BEGIN ADC2_MspInit 1 */

 

 

Do you know if the ContinuousConvMode should be ENABLE or DISABLE ?
And so, do you have an idea on the origin of the wrong value, or on the only one updated value ?

Best regards !

Andrew Neil
Super User
September 20, 2024

Duplicate?

https://community.st.com/t5/stm32-mcus-products/stm32g431kb-adc-wrong-value/td-p/720375

 


@cppoisson wrote:

the ADC is not giving back the right voltage value (which is 0.8V measured with a multimeter) !


So what value is it giving?

Note that a multimeter will give a (relatively) long-term averaged reading, whereas the ADC will give an instantaneous sample ...

 

See also: https://community.st.com/t5/stm32-mcus-boards-and-hardware/adc-voltage-drop/m-p/722300 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
cppoissonAuthor
Associate
September 20, 2024

I created a new topic because I found new details on the problem that I don't undertstand. I didn't notify that if disabled the ContinuousConvMode I had the wright value on the ADC (900 on the ADC equal to 790mV), but the value is not updated. When I am using the ContinuousConvMode the value from the ADC is 150 so 120mV, but this value is updated. 

I also measure the voltage with the osciloscope, I also found a DC 800mV Voltage.

MasterT
Lead II
September 20, 2024

I noticed 

 HAL_ADC_Start_DMA(&hadc2, (uint32_t *) &analog_input.unmap[2], 2);

 

correct code to call adc_dma:

 if (HAL_ADC_Start_DMA(&hadc2, (uint32_t *)inp_1, (2 * INP_BUFF)) != HAL_OK) {

 

 If you post how analog_input.unmap[2] declared in the initial post it would be easier to spot software error.