STM32L031 ADC pin voltage sampling

STM32L031 ADC pin voltage sampling

In order to more accurately reflect the voltage value sampled by the ADC on the pin, the current supply voltage change also needs to be referenced and calculated, which involves the application of STM32 Internal voltage reference (VREFINT).

VREFINT is internally connected to the ADC_IN17 input channel. VREFINT is actually an internally regulated low voltage value, that is, when the chip power supply is applied in a certain range (for example, 1.65V~3.6V), this voltage does not change. However, when the chip ADC power supply (some chips have a separate ADC power supply interface, and some chips ADC power supply is directly connected to the chip power supply), the sampling value of this constant VREFINT will change. ST is shipped from the factory, based on specific The chip supply voltage will store the sampled value of VREFINT in the system storage area, which can be read out and used.

This example is based on STM32CUBEIDE for voltage sampling design of PA0.

ADC configuration

In the configuration interface of STM32CUBEIDE, select ADC and enable IN0 and Vrefint channel sampling.
Insert picture description here
This example uses non-DMA and interruption methods. The configuration parameters are as follows
Insert picture description here
. The code generated by the system after saving is as follows:

ADC_HandleTypeDef hadc;
static void MX_ADC_Init(void);

/**
  * @brief ADC Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC_Init(void)
{
    
    

  /* USER CODE BEGIN ADC_Init 0 */

  /* USER CODE END ADC_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {
    
    0};

  /* USER CODE BEGIN ADC_Init 1 */

  /* USER CODE END ADC_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc.Instance = ADC1;
  hadc.Init.OversamplingMode = DISABLE;
  hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;
  hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ContinuousConvMode = ENABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerFrequencyMode = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_VREFINT;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  /* USER CODE BEGIN ADC_Init 2 */

  /* USER CODE END ADC_Init 2 */

}

/**
* @brief ADC MSP Initialization
* This function configures the hardware resources used in this example
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    
    
  GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
  if(hadc->Instance==ADC1)
  {
    
    
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC GPIO Configuration    
    PA0-CK_IN     ------> ADC_IN0 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    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 */
  }

}

/**
* @brief ADC MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{
    
    
  if(hadc->Instance==ADC1)
  {
    
    
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();
  
    /**ADC GPIO Configuration    
    PA0-CK_IN     ------> ADC_IN0 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);

  /* USER CODE BEGIN ADC1_MspDeInit 1 */

  /* USER CODE END ADC1_MspDeInit 1 */
  }

}

ADC sampling function

The design idea is to obtain the current chip ADC power supply correction voltage (for STM32L031, the same as the chip power supply voltage) based on the sampling and reading of Vrefint before each sampling pin, and compare with the Vrefint value configured at the factory of ST. When sampling the pin voltage, use this real-time corrected voltage as a reference to obtain the corresponding pin voltage value.

Write the single sampling function code as follows:

uint32_t GET_ADC(uint32_t Channel) {
    
    
	uint32_t adc_conv_var;
	extern ADC_HandleTypeDef hadc;
	ADC_ChannelConfTypeDef adcConf;

	__HAL_RCC_ADC1_CLK_ENABLE();

	// Await the the Vrefint used by adc is set
	while (__HAL_PWR_GET_FLAG(PWR_FLAG_VREFINTRDY) == RESET) {
    
    
	};

	// Deselect all channels
	adcConf.Channel = ADC_CHANNEL_MASK;
	adcConf.Rank = ADC_RANK_NONE;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	// Configure adc channel
	adcConf.Channel = Channel;
	adcConf.Rank = ADC_RANK_CHANNEL_NUMBER;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	// Calibrate ADC
	HAL_ADC_Stop(&hadc);
	HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);

	// Start converison
	HAL_ADC_Start(&hadc);

	// Waiting for the end of conversion
	HAL_ADC_PollForConversion(&hadc, 20); // overtime 20ms

	// Read result
	adc_conv_var = HAL_ADC_GetValue(&hadc);

	// Stop
	HAL_ADC_Stop(&hadc);

	// Deselect all channels
	adcConf.Channel = ADC_CHANNEL_MASK;
	adcConf.Rank = ADC_RANK_NONE;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	__HAL_RCC_ADC1_CLK_DISABLE();
	return adc_conv_var;
}

The function to write the average of multiple samples is as follows:

uint32_t GET_ADC_AVG(uint32_t Channel, uint32_t times) {
    
    
	uint32_t adc_conv_var;
	uint64_t adc_acc = 0;
	extern ADC_HandleTypeDef hadc;
	ADC_ChannelConfTypeDef adcConf;
	HAL_StatusTypeDef adc_polling_status;
	uint32_t i;

	__HAL_RCC_ADC1_CLK_ENABLE();

	// Await Vrefint used by adc is set
	while (__HAL_PWR_GET_FLAG(PWR_FLAG_VREFINTRDY) == RESET) {
    
    
	};

	// Deselect all channels
	adcConf.Channel = ADC_CHANNEL_MASK;
	adcConf.Rank = ADC_RANK_NONE;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	// Configure adc channel
	adcConf.Channel = Channel;
	adcConf.Rank = ADC_RANK_CHANNEL_NUMBER;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	// Calibrate ADC
	HAL_ADC_Stop(&hadc);
	HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);


	// Start conversion
	HAL_ADC_Start(&hadc);

	for (i = 0; i < times;) {
    
    
		// Waiting for conversion end
		adc_polling_status = HAL_ADC_PollForConversion(&hadc, 20); // overtime 20ms

		if (adc_polling_status == HAL_OK) {
    
    
			// read data
			adc_acc += (uint64_t) HAL_ADC_GetValue(&hadc);
			i++;
		}
	}
	// Stop
	HAL_ADC_Stop(&hadc);

	// Deselect all channels
	adcConf.Channel = ADC_CHANNEL_MASK;
	adcConf.Rank = ADC_RANK_NONE;
	HAL_ADC_ConfigChannel(&hadc, &adcConf);

	__HAL_RCC_ADC1_CLK_DISABLE();

	adc_conv_var = adc_acc / times;
	return adc_conv_var;
}

Perform sampling and calculate voltage

When ADC sampling and voltage calculation are needed, the Vrefint of STM32L031d is tested under 3V ADC supply voltage and written into the system storage area. If the currently applied ADC supply voltage is 3.3V, write the code as follows:

#define Samle_Times 1000; //Sampling times for average
uint16_t i_VDD_CALI;
uint32_t i_VDD_VALUE;
uint32_t BATTER_VALUE;
double BATTERY_VOL;

        i_VDD_CALI = (*((uint16_t *)(0x1FF80078)))*3/3.3;
		i_VDD_VALUE = GET_ADC(ADC_CHANNEL_17); //Or i_VDD_VALUE = GET_ADC(ADC_CHANNEL_VREFINT);
		BATTER_VALUE = GET_ADC_AVG(ADC_CHANNEL_0, Samle_Times);
		BATTER_VALUE =(uint32_t)(BATTER_VALUE*(((double)i_VDD_CALI)/i_VDD_VALUE));
		BATTERY_VOL = (((double) BATTER_VALUE) / 4096 * 3.3) ;

BATTERY_VOL is the obtained PA0 pin voltage value.

For the sampling of ADC_CHANNEL_VREFINT, you can also use the GET_ADC_AVG() function to use the sampling average according to the situation.

If the method of interrupt or DMA is used, the sampling value correction calculation method of the pin voltage can be modified by referring to the above code.

-End-

Guess you like

Origin blog.csdn.net/hwytree/article/details/103333769