cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 Blue pill - Multichannel ADC in Scan mode reads wrong values

KVenk.8
Associate

Hello,

My objective is:

Read voltage in 10 channels of Blue pill using Scan and Poll conversion mode.

Problem I face is:

  1. Wrong values are read. When I feed 3.3v to the adc input (any input), its adjascent channel reads 3.3v, but that too changes to 2v.
  2. All the channels which are floating reads 1.65v. This I understand as Hold capacitor voltage. It is maintained at Vcc/2. So no problem here.
  3. But when I feed 3.3v to a floating channel, for first scan it reads 3.3v, next scan its adjacent channel reads 3.3v. Likewise it keeps shifting.

What I tried but in vain:

  1. Reduced the ADC clock from 12 MHz to KHz range.
  2. Increased the Sample time from 1.5 cycles to maximum value ~300 cycles.
  3. Take ADC_start out of while(1) and never stop ADC.

Could someone point me where I am doing mistake ?

Somewhere in the community I read scan conversion works best with DMA mode. Is that true ?

PFA my main.c file herewith for reference.

int main(void)
{
  /* USER CODE BEGIN 1 */
char buffer[10];			//used to print adc value on uart1
  /* USER CODE END 1 */
  
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
 
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  //Start the Adc
	  //Wait for the conversion to end
	  //Save the ADC output to 'adc0'
	  //convert the adc0 value to voltage (x100)
	 HAL_ADC_Start(&hadc1);
	 HAL_ADC_PollForConversion(&hadc1, 100);
	 adc0 = HAL_ADC_GetValue(&hadc1);
	 adc0	=	adc0*330/4096;
 
	 //convert the adc0 integer value to float by /100 to get whole no. and %100 to get decimal point. It is then stored as ascii characters in character array 'buffer'
	 //Return value of sprintf is total no. of characters in 'buffer'
	 //print contents of 'buffer' through uart1; print format is "ADC0=3.3"
	 int tx_length  = sprintf(buffer,"%d.%02d",adc0 / 100, adc0 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_0=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	  //Wait for the conversion to end
	  //Save the ADC output to 'adc1'
	  //convert the adc1 value to voltage (x100)
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc1 = HAL_ADC_GetValue(&hadc1);
	 adc1	=	adc1*330/4096;
 
	 tx_length  = sprintf(buffer,"%d.%02d",adc1 / 100, adc1 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_1=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc2 = HAL_ADC_GetValue(&hadc1);
	 adc2	=	adc2*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc2 / 100, adc2 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_2=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc3 = HAL_ADC_GetValue(&hadc1);
	 adc3	=	adc3*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc3 / 100, adc3 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_3=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc4 = HAL_ADC_GetValue(&hadc1);
	 adc4	=	adc4*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc4 / 100, adc4 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_4=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc5 = HAL_ADC_GetValue(&hadc1);
	 adc5	=	adc5*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc5 / 100, adc5 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_5=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc6 = HAL_ADC_GetValue(&hadc1);
	 adc6	=	adc6*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc6 / 100, adc6 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_6=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc7 = HAL_ADC_GetValue(&hadc1);
	 adc7	=	adc7*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc7 / 100, adc7 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_7=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
 
	  HAL_ADC_PollForConversion(&hadc1, 100);
	 adc8 = HAL_ADC_GetValue(&hadc1);
	 adc8	=	adc8*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc8 / 100, adc8 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_8=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	 HAL_ADC_PollForConversion(&hadc1, 100);
	 adc9 = HAL_ADC_GetValue(&hadc1);
	 adc9	=	adc9*330/4096;
	 tx_length  = sprintf(buffer,"%d.%02d",adc9 / 100, adc9 % 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\rADC_9=", 8, 100);
	 HAL_UART_Transmit(&huart1,(uint8_t*)(&buffer),tx_length, 100);
	 HAL_UART_Transmit(&huart1, (uint8_t*)"\n\r", 2, 100);
 
	  HAL_Delay(1000);
 
	  HAL_ADC_Stop(&hadc1);
 
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
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 = 2;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}
 

1 REPLY 1

>>Somewhere in the community I read scan conversion works best with DMA mode. Is that true ?

I think on the F1 it's probably the only way it is going to work without losing sync.

Best to ditch the polled mentality. Use the DMA interrupts it flag the EOC for all channels, and manage the samples in the buffer. Use a buffer holding twice the data, so you can manage the inactive half while the active half fills with new data.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..