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:
void ReadBatteryVoltage(void)
{
float BatVoltage = 0.0;
char VoltageChar[30];
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 value
HAL_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:
/* 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 Configuration
PA4 ------> 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 Configuration
PA4 ------> ADC1_IN4
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
Thank you.