cancel
Showing results for 
Search instead for 
Did you mean: 

ADC Polling Returns Same Value for Each Sample

DRad
Associate

There are four DC fans connected the board.  For each, there is a current resistor buffered through an op-amp and then passed to the ADC channel on the STM32G491RET6 MCU. All four ADCs are connected to the same module on four different channels. 

Software wants to poll into the ADC value periodically and get average (or RMS) current value. This is the code: 

ADC1 configuration: 

 

 

static void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Common config
  */
  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.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = 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.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

 

 

 

Reading the ADC: 

 

 

uint32_t adc_raw;
uint32_t adc_raw_sum = 0;
uint32_t i;

float adc_raw_average;
float adc_voltage;
float voltage;
float current;

#define samples 1000

uint32_t adc_raw_values[samples];

void get_current(uint32_t fan_no)
{
	ADC_ChannelConfTypeDef sConfig = {0};
	/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
	*/
	if (fan_no == 1)
	{
		sConfig.Channel = ADC_CHANNEL_1;
	}
	else if (fan_no == 2)
	{
		sConfig.Channel = ADC_CHANNEL_2;
	}
	else if (fan_no == 3)
	{
		sConfig.Channel = ADC_CHANNEL_3;
	}
	else if (fan_no == 4)
	{
		sConfig.Channel = ADC_CHANNEL_4;
	}

	sConfig.Rank = ADC_REGULAR_RANK_1;
	sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
	sConfig.SingleDiff = ADC_SINGLE_ENDED;
	sConfig.OffsetNumber = ADC_OFFSET_NONE;
	sConfig.Offset = 0;

	if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
	{
		Error_Handler();
	}


	/* Get ADC value */
	adc_raw_sum = 0;
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);

	for (i = 0; i<samples; i++)
	{
		adc_raw = HAL_ADC_GetValue(&hadc1);
		adc_raw_values[i] = adc_raw;
		adc_raw_sum = adc_raw_sum + adc_raw;
		delay_us(4);
	}
	adc_raw_average = adc_raw_sum/samples;
	adc_voltage = adc_raw_average * 0.00081;
	voltage = adc_voltage/50;
	current = voltage/0.13;
	HAL_ADC_Stop(&hadc1);
}

 

 


I would adjust the match to get actual RMS value. For now I just calculate mean.

Period of the signal fed to ADC module is 3.5ms. Rounded to 4ms, and with 1000 samples taken for one reading, added delay after each sampling is 4us. In this way, we sample at every 4us and within 1000 samples, the entire period of the signal gets covered. 

The problem is that all 1000 samples are always the same. They vary over time (range 50-3500 or so), but they are always equal to each other. 

Any help regarding what I could be doing wrong here would be appreciated. 

1 ACCEPTED SOLUTION

Accepted Solutions
KnarfB
Principal III

HAL_ADC_GetValue only reads the result. You should repeat a complete HAL_ADC_Start, HAL_ADC_PollForConversion, HAL_ADC_GetValue, HAL_ADC_Stop sequence for each new measurement.

hth

KnarfB

View solution in original post

2 REPLIES 2
KnarfB
Principal III

HAL_ADC_GetValue only reads the result. You should repeat a complete HAL_ADC_Start, HAL_ADC_PollForConversion, HAL_ADC_GetValue, HAL_ADC_Stop sequence for each new measurement.

hth

KnarfB

KnarfB
Principal III

side note: when  accurate timing is required, you may trigger an ADC measurement by a periodic timer, not by software. Many ADCs are also capable of averaging multiple measurements internally (oversampling).

hth

KnarfB