cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G431KB ADC Wrong value

cppoisson
Associate II

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.

13 REPLIES 13
Imen.D
ST Employee

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

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
MasterT
Lead
  sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

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

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 !

than line of code should be changed:

sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

to

sConfig.Channel = ADC_CHANNEL_VOPAMP2;

This configuration is already given in the first regular chanel of the ADC 2. 
 
Best regards.

ll_motor_GetVoltage

I'm not familiar with this function, likely part of motor software package, have a link?

 

    return (((float)analog_input.voltage * VREF_ADC) / (ADC_RESOLUTION));

 

 and post definition of analog_input.voltage /vref_adc / adc_relosution.

Yes it is but I am debuging the adc value before this function is called. I just put it to give the context avec the struct analog_input.unmap[2] wich is linked to analog_input.voltage. 

For debugging I'd suggest to split adc-opa structure in separate modules, routing opa output to external GPIO than compare IN - OUT voltages (should be the same in follower mode),  and link external pin to adc input creating rank3 channel on free accessable GPIO - verify adc raw data readings vs input voltages

cppoisson
Associate II

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 !