STM32G0 ADC low value - Page 1
Forum section: electronics / general

author: Veketti
author_rank: Regular Contributor
timestamp: February 06, 2024, 05:11:17 pm
content: Dear All,I added to my CO meter battery voltage measurement when the device is turned on. So single shot ADC measurement. However the measured value is too small and it drifts more, higher the voltage. Eg. real value of 2.495V -> ADC show 0.195V lower value. Real value 2.797V -> ADC show 0.227V lower value. I measured voltages from the MCU pin which reads the ADC. VREF+, VBAT and VDDA are all connected to same rail having 3.333V. I quess this ADC cannot be so inaccurate, so I must once again be doing something wrong? MCU is STM32G070CBT6. I could of course add 0.2 for the value to get close and forget it, but I'd like to understand where's my mistake, so hopefully someone could help to point it out?Here's the read function:Code:void ReadBatteryVoltage(void){float BatVoltage = 0.0;char VoltageChar;uint16_t adc_val = 0;if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK) // Calibrate the ADC{Error_Handler();}HAL_Delay(100);if (HAL_ADC_Start(&hadc1)!= HAL_OK){Error_Handler();}if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK){Error_Handler();}adc_val = HAL_ADC_GetValue(&hadc1); // get the adc valueHAL_ADC_Stop(&hadc1); // stop adc. I'm not sure is this needed though as it is singe shot?BatVoltage = adc_val / 4096.0f * 3.3f;And here's the initialisation:Code:/* ADC1 init function */void MX_ADC1_Init(void){/* USER CODE BEGIN ADC1_Init 0 *//* USER CODE END ADC1_Init 0 */ADC_ChannelConfTypeDef sConfig = {0};/* USER CODE BEGIN ADC1_Init 1 *//* USER CODE END ADC1_Init 1 *//** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc1.Init.LowPowerAutoWait = DISABLE;hadc1.Init.LowPowerAutoPowerOff = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.NbrOfConversion = 1;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.DMAContinuousRequests = DISABLE;hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;hadc1.Init.OversamplingMode = DISABLE;hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_4;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC1_Init 2 *//* USER CODE END ADC1_Init 2 */}void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle){GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspInit 0 *//* USER CODE END ADC1_MspInit 0 *//* ADC1 clock enable */__HAL_RCC_ADC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**ADC1 GPIO ConfigurationPA4 ------> ADC1_IN4*/GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN ADC1_MspInit 1 *//* USER CODE END ADC1_MspInit 1 */}}void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle){if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspDeInit 0 *//* USER CODE END ADC1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ADC_CLK_DISABLE();/**ADC1 GPIO ConfigurationPA4 ------> ADC1_IN4*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);/* USER CODE BEGIN ADC1_MspDeInit 1 *//* USER CODE END ADC1_MspDeInit 1 */}}Thank you.

author: wek
author_rank: Frequent Contributor
timestamp: February 07, 2024, 12:50:30 pm
content: What's the impedance of input voltage?> hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;This is probably too short. Try longer.JW

author: tszaboo
author_rank: Super Contributor
timestamp: February 07, 2024, 01:06:00 pm
content: Source impedance for example as mentioned. Place a scope on the input pin, you might see a dip or peak (value and architecture dependent) when it's sampling. If you place a 100nF or so capacitor on the ADC pin it might go away.

author: Veketti
author_rank: Regular Contributor
timestamp: February 07, 2024, 04:36:33 pm
content: That's it. I had 10k series resistor between the battery and adc input, so it had dip when the input charged. I changed the SamplingTimeCommon1 to ADC_SAMPLETIME_79CYCLES_5 and now the value is spot on!Thank you so much for help and also that link that explains the behaviour.

author: harerod
author_rank: Frequent Contributor
timestamp: February 09, 2024, 08:37:04 pm
content: Have a look at the reference manual to understand the internal structure of the ADC. During sampling a switch will connect an internal sampling capacitor to the signal source. That internal capacitor must be charged to the signal voltage within the required accuracy during the sampling time. If you add a small buffer capacitor which is much larger than the sampling capacitor, you provide sufficient charge.Not so important for DC signals, yet usually a requirement for A-to-D conversion, is the avoidance of signal frequencies around half the sampling frequency and above (see Nyquist frequency). An RC combination with adequate time constant does the trick for many applications.So adding a buffer capacitor to your resistor will provide two important functions.

author: DavidAlfa
author_rank: Super Contributor
timestamp: February 09, 2024, 10:21:01 pm
content: Haha classic one!The ADC has a sampling capacitor in the order of 8-10pF, it's charged for the specific sampling time, then the pin is internally disconnected and the conversion begins.This is called sample-and-hold technique.If the sampling is too fast, the cap doesn't fully charge and you get that problem.Try different values, once you see no difference between two settings you might use the latter one or even slightly larger to provide some margin.

author: Veketti
author_rank: Regular Contributor
timestamp: February 10, 2024, 10:04:01 am
content: Opened new thread, so please disregard this post.

author: wek
author_rank: Frequent Contributor
timestamp: February 10, 2024, 12:53:04 pm
content: You should really start a new thread with new questions.JW