Skip to main content
Graduate
September 16, 2024
Question

STM32G431KB ADC Wrong value

  • September 16, 2024
  • 4 replies
  • 2524 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.

    This topic has been closed for replies.

    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

    Explorer
    September 16, 2024
     sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

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

    cppoissonAuthor
    Graduate
    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 !

    Explorer
    September 19, 2024

    than line of code should be changed:

    sConfig.Channel = ADC_CHANNEL_VOPAMP3_ADC2;

    to

    sConfig.Channel = ADC_CHANNEL_VOPAMP2;

    cppoissonAuthor
    Graduate
    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 !

    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 

    cppoissonAuthor
    Graduate
    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.

    Explorer
    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.