cancel
Showing results for 
Search instead for 
Did you mean: 

How can I read 4 inputs of ADC continously (using HAL)

chriskuku
Senior II

I have initialized ADC1 and assigned it 4 channels (PA4-PA7 as IN4 to IN7). My initialization looks like this:

static 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 */
 
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  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_SAMPLETIME_1CYCLE_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}

I would like to read all 4 channels one after another (they represent pot positions). How can I address each channel? This is the code I'm trying but I don't see any specific channel being addressed. Rather than the one specified in the initialization.

The is the read loop:

while (1)
  {
	 char buffer[8];
	 int ADCValue;
    /* USER CODE BEGIN 3 */
	  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
	  	 //delay_us(50);
	  delay_ms(10);
	  	 //pin_state = !pin_state;
	  	 //HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, pin_state);
	  	 // synchronous delay for 500 ms
	  	 //HAL_Delay(100);
	  if (HAL_ADC_Start(&hadc1) != HAL_OK)
	  {
	      /* Start Conversation Error */
	       Error_Handler();
	  }
	  if (HAL_ADC_PollForConversion(&hadc1, 500) != HAL_OK)
	  {
	      /* End Of Conversion flag not set on time */
	      // Error_Handler();
	      ADCValue=-1;
	  }
	  else
	  {
	      /* ADC conversion completed */
	      ADCValue = HAL_ADC_GetValue(&hadc1);
	  }
	  HAL_ADC_Stop(&hadc1);
 
	  sprintf(buffer,"%d",ADCValue);
	  lcd_setcursor(0,1);
	  lcd_string(buffer);
	  /* USER CODE END 3 */
  }

7 REPLIES 7
S.Ma
Principal

Which STM32? There are many different versions.

raptorhal2
Lead

Add configuration for IN5 to IN7 as ranks 2 to 4, Make nbrofconversion = 4

Edit: And since there is only one ADC conversion result register, save the results into a 4 16bit word buffer using DMA. Without DMA you could poll for each channel and reconfigure the ADC for the next conversion after each conversion, but that would not be compatible with the continuous conversion goal.

And reading pots with few sample cycles usually results in inaccurate results. See ST's Application Note AN2834 for more information.

Sorry, forgot: STM32F103C8T6

@raptorhal2​ Thanks for pointing me to that AN2834. It is a very voluminous document covering ADC errors and accuracy. Averaging samples is also mentioned. Nothing about pots in particular.

And programming examples for setting up DMA and the desired 4 channel configuration would be very welcome at the moment. Averaging comes later :)

raptorhal2
Lead

Nothing about pots in particular.

A pot is a high impedance device. How high depends on the pot and setting. The output of an operational amplifier would be a low impedance device, where 1,5 cycles could be used.

programming examples for setting up DMA

The Standard Peripheral and HAL libraries for the F103 come with ADC DMA examples. You may have to expand the example buffer size and configuration ranks to 4.

chriskuku
Senior II

Sorry, misedited.

chriskuku
Senior II
static 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 */
 
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 4;
  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_SAMPLETIME_1CYCLE_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_7;
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}

I'm still doing something wrong. ADC values are not sorted in as expected:

ADC: 1839 2112 0 1257 
ADC: 1263 2112 0 1257 
ADC: 1254 1835 2107 1 
ADC: 0 1258 1839 2111 
ADC: 6 1262 1840 2107 
ADC: 2108 1 1257 1836
void StartTask03(void *argument)
{
  /* USER CODE BEGIN StartTask03 */
	// ADC CAlibration
	HAL_ADCEx_Calibration_Start(&hadc1);
	osDelay(50);
	
  /* Infinite loop */
  for(;;)
  {
      char str[32];
 
	  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&adc_value[0], 4);
	  sprintf(str,"ADC: %d %d %d %d \n",adc_value[0],adc_value[1],adc_value[2],adc_value[3]);
	  uart1_print(str);
   
	  osDelay(5000);
  }
  /* USER CODE END StartTask03 */
}